我正在编写一个应该检测VPN流量的程序。 就我读到的主题而言,似乎隧道协议的检测很容易作为防火墙规则,使用它们的专用端口:
PPTP:端口1723 / TCP
OpenVPN:端口1194
L2TP:端口1701 / UDP
我的问题在于SSTP,因为它使用的是广泛使用的端口443。
所以我有两个问题:
我正在附加一段Python代码,用于检测上述端口中的通信
import dpkt
import socket
# -------------------------- Globals
# VPN PORTS
import common
import dal
protocols_strs = {"pp2e_gre": "1723/TCP PP2P_GRE_PORT",
"openvpn": "1194 OPENVPN_PORT",
"ike": "500/UDP IKE_PORT",
"l2tp_ipsec": "1701/UDP L2TP_IPSEC_PORT"
}
port_protocols = {1723: 'pp2e_gre',
1194: 'openvpn',
500: 'ike',
1701: 'l2tp_ipsec'
}
# Dict of sets holding the protocols sessions
protocol_sessions = {"pp2e_gre": [],
"openvpn": [],
"ike": [],
"l2tp_ipsec": []}
# -------------------------- Functions
def is_bidirectional(five_tuple, protocol):
"""
Given a tuple and protocol check if the connection is bidirectional in the protocol
:param five_tuple:
:return: True of the connection is bidirectional False otherwise
"""
src_ip = five_tuple['src_ip']
dest_ip = five_tuple['dest_ip']
# Filter the sessions the five tuple's ips spoke in
ike_sessions = filter(lambda session: (session['src_ip'] == src_ip and session['dest_ip'] == dest_ip)
or
(session['dest_ip'] == src_ip and session['src_ip'] == dest_ip),
protocol_sessions[protocol])
# Return true if 2 session (1 for each direction) were found
return len(ike_sessions) == 2
def print_alert(timestamp, protocol, five_tuple):
"""
Print alert description to std
:param timestamp:
:param protocol:
:param five_tuple:
:return:
"""
print timestamp, ":\t detected port %s communication (%s:%s ---> %s:%s)" % \
(protocol, five_tuple['src_ip'], five_tuple['src_port'], five_tuple['dest_ip'],
five_tuple['dest_port'])
def pp2e_gre_openvpn_ike_handler(five_tuple):
# Get protocol
protocol = five_tuple['protocol']
# Clear old sessions in db
dal.remove_old_sessions(five_tuple['timestamp'], 'vpn_sessions')
# Clear old sessions in cache
protocol_sessions[protocol] = common.clear_old_sessions(five_tuple, protocol_sessions[protocol])
# If session already exists - return
if common.check_if_session_exists(five_tuple, protocol_sessions[protocol]):
session_to_update = common.get_session(five_tuple, protocol_sessions[protocol])
session_to_update['timestamp'] = five_tuple['timestamp']
return
# Update DB
dal.upsert_vpn_session(five_tuple)
# Add to cache
protocol_sessions[protocol].append(five_tuple)
# Print alert
print_alert(five_tuple['timestamp'], protocols_strs[protocol], five_tuple)
def l2tp_ipsec_handler(five_tuple):
if five_tuple in protocol_sessions['l2tp_ipsec']:
return
# If bi-directional IKE protocol performed earlier - alert
if not is_bidirectional(five_tuple, 'ike'):
return
protocol_sessions['l2tp_ipsec'].append(five_tuple)
print_alert(five_tuple['timestamp'], protocols_strs['l2tp_ipsec'], five_tuple)
# -------------------------- VPN ports jump tables
tcp_vpn_ports = {1723: pp2e_gre_openvpn_ike_handler,
1194: pp2e_gre_openvpn_ike_handler}
udp_vpn_ports = {500: pp2e_gre_openvpn_ike_handler,
1701: l2tp_ipsec_handler,
1194: pp2e_gre_openvpn_ike_handler}
# -------------------------- Functions
def process_packet(timestamp, packet):
"""
Given a packet process it for detecting a VPN communication
:param packet:
:param timestamp:
:return:
"""
# Parse the input
eth_frame = dpkt.ethernet.Ethernet(packet)
# Check if IP
if eth_frame.type != dpkt.ethernet.ETH_TYPE_IP:
return
# If not IP return
ip_frame = eth_frame.data
# if TCP or UDP
if ip_frame.p not in (dpkt.ip.IP_PROTO_TCP, dpkt.ip.IP_PROTO_UDP):
return
# Extract L3 frame
frame = ip_frame.data
# Extract ports
frame_ports = (frame.sport, frame.dport)
# get VPN ports in session
detected_ports = set(tcp_vpn_ports).intersection(frame_ports)
# If TCP VPN port was not detected return
if not detected_ports:
return
# Get detected port
port = detected_ports.pop()
# Translate port to str
protocol_str = port_protocols[port]
# Choose handler by port
handler = tcp_vpn_ports[port]
# Extract 5-tuple parameters from frames
five_tuple = {'src_ip': socket.inet_ntoa(ip_frame.src),
'dest_ip': socket.inet_ntoa(ip_frame.dst),
'src_port': frame.sport,
'dest_port': frame.dport,
'protocol': protocol_str,
'timestamp': timestamp}
# Invoke the chosen handler
handler(five_tuple)