|
12 | 12 | import sys
|
13 | 13 | from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
|
14 | 14 | from helpers import log, debug1, debug2, debug3, Fatal, islocal
|
| 15 | +from fcntl import ioctl |
| 16 | +from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, sizeof, addressof, memmove |
15 | 17 |
|
16 | 18 | recvmsg = None
|
17 | 19 | try:
|
@@ -185,6 +187,79 @@ def daemon_cleanup():
|
185 | 187 | raise
|
186 | 188 |
|
187 | 189 |
|
| 190 | +class pf_state_xport(Union): |
| 191 | + _fields_ = [("port", c_uint16), |
| 192 | + ("call_id", c_uint16), |
| 193 | + ("spi", c_uint32)] |
| 194 | + |
| 195 | +class pf_addr(Structure): |
| 196 | + class _pfa(Union): |
| 197 | + _fields_ = [("v4", c_uint32), # struct in_addr |
| 198 | + ("v6", c_uint32 * 4), # struct in6_addr |
| 199 | + ("addr8", c_uint8 * 16), |
| 200 | + ("addr16", c_uint16 * 8), |
| 201 | + ("addr32", c_uint32 * 4)] |
| 202 | + |
| 203 | + _fields_ = [("pfa", _pfa)] |
| 204 | + _anonymous_ = ("pfa",) |
| 205 | + |
| 206 | +class pfioc_natlook(Structure): |
| 207 | + _fields_ = [("saddr", pf_addr), |
| 208 | + ("daddr", pf_addr), |
| 209 | + ("rsaddr", pf_addr), |
| 210 | + ("rdaddr", pf_addr), |
| 211 | + ("sxport", pf_state_xport), |
| 212 | + ("dxport", pf_state_xport), |
| 213 | + ("rsxport", pf_state_xport), |
| 214 | + ("rdxport", pf_state_xport), |
| 215 | + ("af", c_uint8), # sa_family_t |
| 216 | + ("proto", c_uint8), |
| 217 | + ("proto_variant", c_uint8), |
| 218 | + ("direction", c_uint8)] |
| 219 | + |
| 220 | +DIOCNATLOOK = ((0x40000000L | 0x80000000L) | ((sizeof(pfioc_natlook) & 0x1fff) << 16) | ((ord('D')) << 8) | (23)) |
| 221 | +PF_OUT = 2 |
| 222 | + |
| 223 | +_pf_fd = None |
| 224 | + |
| 225 | +def pf_dst(sock): |
| 226 | + global _pf_fd |
| 227 | + try: |
| 228 | + peer = sock.getpeername() |
| 229 | + proxy = sock.getsockname() |
| 230 | + |
| 231 | + pnl = pfioc_natlook() |
| 232 | + pnl.proto = socket.IPPROTO_TCP |
| 233 | + pnl.direction = PF_OUT |
| 234 | + if sock.family == socket.AF_INET: |
| 235 | + pnl.af = socket.AF_INET |
| 236 | + memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET, peer[0]), 4) |
| 237 | + pnl.sxport.port = socket.htons(peer[1]) |
| 238 | + memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET, proxy[0]), 4) |
| 239 | + pnl.dxport.port = socket.htons(proxy[1]) |
| 240 | + elif sock.family == socket.AF_INET6: |
| 241 | + pnl.af = socket.AF_INET6 |
| 242 | + memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET6, peer[0]), 16) |
| 243 | + pnl.sxport.port = socket.htons(peer[1]) |
| 244 | + memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET6, proxy[0]), 16) |
| 245 | + pnl.dxport.port = socket.htons(proxy[1]) |
| 246 | + |
| 247 | + if _pf_fd == None: |
| 248 | + _pf_fd = open('/dev/pf', 'r') |
| 249 | + |
| 250 | + ioctl(_pf_fd, DIOCNATLOOK, (c_char * sizeof(pnl)).from_address(addressof(pnl))) |
| 251 | + |
| 252 | + if pnl.af == socket.AF_INET: |
| 253 | + ip = socket.inet_ntop(socket.AF_INET, (c_char * 4).from_address(addressof(pnl.rdaddr))) |
| 254 | + elif pnl.af == socket.AF_INET6: |
| 255 | + ip = socket.inet_ntop(socket.AF_INET6, (c_char * 16).from_address(addressof(pnl.rdaddr))) |
| 256 | + port = socket.ntohs(pnl.rdxport.port) |
| 257 | + return (ip, port) |
| 258 | + except IOError, e: |
| 259 | + return sock.getsockname() |
| 260 | + raise |
| 261 | + |
| 262 | + |
188 | 263 | def original_dst(sock):
|
189 | 264 | try:
|
190 | 265 | SO_ORIGINAL_DST = 80
|
@@ -381,6 +456,8 @@ def onaccept_tcp(listener, method, mux, handlers):
|
381 | 456 | raise
|
382 | 457 | if method == "tproxy":
|
383 | 458 | dstip = sock.getsockname()
|
| 459 | + elif method == "pf": |
| 460 | + dstip = pf_dst(sock) |
384 | 461 | else:
|
385 | 462 | dstip = original_dst(sock)
|
386 | 463 | debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1],
|
|
0 commit comments