Skip to content

Instantly share code, notes, and snippets.

@chenzhuoyu
Created August 15, 2017 08:40
Show Gist options
  • Save chenzhuoyu/3040ca3edad97b407a8ab7ec591160a0 to your computer and use it in GitHub Desktop.
Save chenzhuoyu/3040ca3edad97b407a8ab7ec591160a0 to your computer and use it in GitHub Desktop.
Get original dest addr for FreeBSD pf
import os
import fcntl
import ctypes
import socket
import struct
PF_OUT = 2
DIOCNATLOOK = 0xc04c4417
class pf_addr(ctypes.Structure):
class _pfa(ctypes.Union):
_fields_ = [
('v4', ctypes.c_uint32),
('v6', ctypes.c_uint32 * 4),
('addr8', ctypes.c_uint8 * 16),
('addr16', ctypes.c_uint16 * 8),
('addr32', ctypes.c_uint32 * 4),
]
_fields_ = [('pfa', _pfa)]
_anonymous_ = ('pfa',)
class pfioc_natlook(ctypes.Structure):
_fields_ = [
('saddr', pf_addr),
('daddr', pf_addr),
('rsaddr', pf_addr),
('rdaddr', pf_addr),
('sport', ctypes.c_uint16),
('dport', ctypes.c_uint16),
('rsport', ctypes.c_uint16),
('rdport', ctypes.c_uint16),
('af', ctypes.c_uint8),
('proto', ctypes.c_uint8),
('direction', ctypes.c_uint8),
]
def get_orig_dst(sock):
saddr, sport = sock.getpeername()
daddr, dport = sock.getsockname()
nl = pfioc_natlook()
nl.saddr.v4, = struct.unpack('<I', socket.inet_aton(saddr))
nl.daddr.v4, = struct.unpack('<I', socket.inet_aton(daddr))
nl.sport = socket.htons(sport)
nl.dport = socket.htons(dport)
nl.af = socket.AF_INET
nl.proto = socket.IPPROTO_TCP
nl.direction = PF_OUT
fd = os.open('/dev/pf', os.O_RDONLY)
fcntl.ioctl(fd, DIOCNATLOOK, nl)
os.close(fd)
rdaddr = socket.inet_ntoa(struct.pack('<I', nl.rdaddr.v4))
rdport = socket.ntohs(nl.rdport)
return rdaddr, rdport
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 10080))
s.listen(1)
while True:
c, _ = s.accept()
print get_orig_dst(c)
c.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment