18 ipbytes = map(ord,ip.decode("hex"))
19 return '.'.join(map(str,ipbytes))
25 '8863' : 'PPPoE discover',
29 def etherProto(packet, len=len):
31 if packet[12] == "\x81" and packet[13] == "\x00":
39 def formatPacket(packet, ether_mode):
41 stripped_packet = etherStrip(packet)
42 if not stripped_packet:
43 packet = packet.encode("hex")
45 return "malformed eth " + packet.encode("hex")
47 if packet[24:28] == "8100":
49 ethertype = tagtype.get(packet[32:36], 'eth')
50 return ethertype + " " + ( '-'.join( (
51 packet[0:12], # MAC dest
52 packet[12:24], # MAC src
53 packet[24:32], # VLAN tag
54 packet[32:36], # Ethertype/len
55 packet[36:], # Payload
59 ethertype = tagtype.get(packet[24:28], 'eth')
60 return ethertype + " " + ( '-'.join( (
61 packet[0:12], # MAC dest
62 packet[12:24], # MAC src
63 packet[24:28], # Ethertype/len
64 packet[28:], # Payload
67 packet = stripped_packet
68 packet = packet.encode("hex")
70 return "malformed ip " + packet
72 return "ip " + ( '-'.join( (
74 packet[1:2], #header length
75 packet[2:4], #diffserv/ECN
76 packet[4:8], #total length
78 packet[12:16], #flags/fragment offs
80 packet[18:20], #ip-proto
81 packet[20:24], #checksum
82 ipfmt(packet[24:32]), # src-ip
83 ipfmt(packet[32:40]), # dst-ip
84 packet[40:48] if (int(packet[1],16) > 5) else "", # options
85 packet[48:] if (int(packet[1],16) > 5) else packet[40:], # payload
88 def _packetReady(buf, ether_mode=False, len=len, str=str):
99 _,totallen = struct.unpack('HH',buf[0][:4])
100 totallen = socket.htons(totallen)
101 rv = len(buf[0]) >= totallen
102 if not rv and len(buf) > 1:
103 # collapse only first two buffers
104 # as needed, to mantain len(buf) meaningful
106 buf[0] = p1+str(buf[0])
111 def _pullPacket(buf, ether_mode=False, len=len, buffer=buffer):
115 _,totallen = struct.unpack('HH',buf[0][:4])
116 totallen = socket.htons(totallen)
117 if len(buf[0]) > totallen:
118 rv = buffer(buf[0],0,totallen)
119 buf[0] = buffer(buf[0],totallen)
124 def etherStrip(buf, buffer=buffer, len=len):
127 if buf[12:14] == '\x08\x10' and buf[16:18] == '\x08\x00':
128 # tagged ethernet frame
129 return buffer(buf, 18)
130 elif buf[12:14] == '\x08\x00':
131 # untagged ethernet frame
132 return buffer(buf, 14)
136 def etherWrap(packet):
138 "\x00"*6*2 # bogus src and dst mac
141 "\x00"*4, # bogus crc
144 def piStrip(buf, len=len):
150 def piWrap(buf, ether_mode, etherProto=etherProto):
152 proto = etherProto(buf)
156 "\x00\x00", # PI: 16 bits flags
157 proto, # 16 bits proto
161 _padmap = [ chr(padding) * padding for padding in xrange(127) ]
164 def encrypt(packet, crypter, len=len, padmap=_padmap):
166 padding = crypter.block_size - len(packet) % crypter.block_size
167 packet += padmap[padding]
170 return crypter.encrypt(packet)
172 def decrypt(packet, crypter, ord=ord):
175 packet = crypter.decrypt(packet)
178 padding = ord(packet[-1])
179 if not (0 < padding <= crypter.block_size):
181 raise RuntimeError, "Truncated packet"
182 packet = packet[:-padding]
188 fl = fcntl.fcntl(fd, fcntl.F_GETFL)
190 fcntl.fcntl(fd, fcntl.F_SETFL, fl)
193 traceback.print_exc(file=sys.stderr)
197 def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr=sys.stderr, reconnect=None, rwrite=None, rread=None, tunqueue=1000, tunkqueue=1000,
198 cipher='AES', accept_local=None, accept_remote=None, slowlocal=True, queueclass=None, bwlimit=None,
199 len=len, max=max, min=min, buffer=buffer, OSError=OSError, select=select.select, selecterror=select.error, os=os, socket=socket,
200 retrycodes=(os.errno.EWOULDBLOCK, os.errno.EAGAIN, os.errno.EINTR) ):
205 if cipher_key and cipher:
208 __import__('Crypto.Cipher.'+cipher)
211 cipher = getattr(Crypto.Cipher, cipher)
212 hashed_key = hashlib.sha256(cipher_key).digest()
213 if getattr(cipher, 'key_size'):
214 hashed_key = hashed_key[:cipher.key_size]
215 elif ciphername == 'DES3':
216 hashed_key = hashed_key[:24]
217 crypter = cipher.new(
222 traceback.print_exc(file=sys.stderr)
226 if stderr is not None:
228 print >>stderr, "Packets are transmitted in CIPHER"
230 print >>stderr, "Packets are transmitted in PLAINTEXT"
232 if hasattr(remote, 'fileno'):
233 remote_fd = remote.fileno()
235 def rwrite(remote, packet, os_write=os.write):
236 return os_write(remote_fd, packet)
238 def rread(remote, maxlen, os_read=os.read):
239 return os_read(remote_fd, maxlen)
241 rnonblock = nonblock(remote)
242 tnonblock = nonblock(tun)
244 # Pick up TUN/TAP writing method
249 # We have iovec, so we can skip PI injection
250 # and use iovec which does it natively
252 twrite = iovec.ethpiwrite
253 tread = iovec.piread2
255 twrite = iovec.ippiwrite
256 tread = iovec.piread2
258 # We have to inject PI headers pythonically
259 def twrite(fd, packet, oswrite=os.write, piWrap=piWrap, ether_mode=ether_mode):
260 return oswrite(fd, piWrap(packet, ether_mode))
262 # For reading, we strip PI headers with buffer slicing and that's it
263 def tread(fd, maxlen, osread=os.read, piStrip=piStrip):
264 return piStrip(osread(fd, maxlen))
266 # No need to inject PI headers
274 if accept_local is not None:
275 def tread(fd, maxlen, _tread=tread, accept=accept_local):
276 packet = _tread(fd, maxlen)
277 if accept(packet, 0):
282 if accept_remote is not None:
284 def decrypt_(packet, crypter, decrypt_=decrypt_, accept=accept_remote):
285 packet = decrypt_(packet, crypter)
286 if accept(packet, 1):
291 def rread(fd, maxlen, _rread=rread, accept=accept_remote):
292 packet = _rread(fd, maxlen)
293 if accept(packet, 1):
298 maxbkbuf = maxfwbuf = max(10,tunqueue-tunkqueue)
299 tunhurry = max(0,maxbkbuf/2)
301 if queueclass is None:
302 queueclass = collections.deque
306 maxfwbuf = maxbkbuf = 2000000000
316 # backwards queue functions
317 # they may need packet inspection to
318 # reconstruct packet boundaries
319 if ether_mode or udp:
321 pullPacket = queueclass.popleft
322 reschedule = queueclass.appendleft
324 packetReady = _packetReady
325 pullPacket = _pullPacket
326 reschedule = queueclass.appendleft
328 # forward queue functions
329 # no packet inspection needed
331 fpullPacket = queueclass.popleft
332 freschedule = queueclass.appendleft
339 maxbwfree = bwfree = 1500 * tunqueue
347 if packetReady(bkbuf):
349 if remoteok and fpacketReady(fwbuf) and (not bwlimit or bwfree > 0):
353 if len(fwbuf) < maxfwbuf:
355 if remoteok and len(bkbuf) < maxbkbuf:
364 rdrdy, wrdy, errs = select(rset,wset,eset,1)
365 except selecterror, e:
366 if e.args[0] == errno.EINTR:
370 traceback.print_exc(file=sys.stderr)
375 if reconnect is not None and remote in errs and tun not in errs:
377 if hasattr(remote, 'fileno'):
378 remote_fd = remote.fileno()
379 elif udp and remote in errs and tun not in errs:
380 # In UDP mode, those are always transient errors
381 # Usually, an error will imply a read-ready socket
382 # that will raise an "Connection refused" error, so
383 # disable read-readiness just for now, and retry
392 # check to see if we can write
393 #rr = wr = rt = wt = 0
398 for x in xrange(maxbatch):
399 packet = pullPacket(fwbuf)
402 packet = encrypt_(packet, crypter)
404 sentnow = rwrite(remote, packet)
408 if not udp and 0 <= sentnow < len(packet):
409 # packet partially sent
410 # reschedule the remaining part
411 # this doesn't happen ever in udp mode
412 freschedule(fwbuf, buffer(packet,sentnow))
414 if not rnonblock or not fpacketReady(fwbuf):
417 # This except handles the entire While block on PURPOSE
418 # as an optimization (setting a try/except block is expensive)
419 # The only operation that can raise this exception is rwrite
420 if e.errno in retrycodes:
422 freschedule(fwbuf, packet)
426 if reconnect is not None:
427 # in UDP mode, sometimes connected sockets can return a connection refused.
428 # Give the caller a chance to reconnect
430 if hasattr(remote, 'fileno'):
431 remote_fd = remote.fileno()
433 # in UDP mode, we ignore errors - packet loss man...
435 #traceback.print_exc(file=sys.stderr)
441 for x in xrange(maxtbatch):
442 packet = pullPacket(bkbuf)
443 twrite(tunfd, packet)
446 # Do not inject packets into the TUN faster than they arrive, unless we're falling
447 # behind. TUN devices discard packets if their queue is full (tunkqueue), but they
448 # don't block either (they're always ready to write), so if we flood the device
449 # we'll have high packet loss.
450 if not tnonblock or (slowlocal and len(bkbuf) < tunhurry) or not packetReady(bkbuf):
454 # Give some time for the kernel to process the packets
457 # This except handles the entire While block on PURPOSE
458 # as an optimization (setting a try/except block is expensive)
459 # The only operation that can raise this exception is os_write
460 if e.errno in retrycodes:
462 reschedule(bkbuf, packet)
466 # check incoming data packets
469 for x in xrange(maxbatch):
470 packet = tread(tunfd,2000) # tun.read blocks until it gets 2k!
476 if not tnonblock or len(fwbuf) >= maxfwbuf:
479 # This except handles the entire While block on PURPOSE
480 # as an optimization (setting a try/except block is expensive)
481 # The only operation that can raise this exception is os_read
482 if e.errno not in retrycodes:
487 for x in xrange(maxbatch):
488 packet = rread(remote,2000)
493 packet = decrypt_(packet, crypter)
497 if not udp and packet == "":
498 # Connection broken, try to reconnect (or just die)
499 raise RuntimeError, "Connection broken"
505 if not rnonblock or len(bkbuf) >= maxbkbuf:
508 # This except handles the entire While block on PURPOSE
509 # as an optimization (setting a try/except block is expensive)
510 # The only operation that can raise this exception is rread
511 if e.errno not in retrycodes:
514 if reconnect is not None:
515 # in UDP mode, sometimes connected sockets can return a connection refused
516 # on read. Give the caller a chance to reconnect
518 if hasattr(remote, 'fileno'):
519 remote_fd = remote.fileno()
521 # in UDP mode, we ignore errors - packet loss man...
523 traceback.print_exc(file=sys.stderr)
527 delta = tnow - lastbwtime
529 delta = int(bwlimit * delta)
531 bwfree = min(bwfree+delta, maxbwfree)
534 #print >>sys.stderr, "rr:%d\twr:%d\trt:%d\twt:%d" % (rr,wr,rt,wt)
536 def udp_connect(TERMINATE, local_addr, local_port, peer_addr, peer_port):
537 rsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
540 # TERMINATE is a array. An item can be added to TERMINATE, from
541 # outside this function to force termination of the loop
543 raise OSError, "Killed"
545 rsock.bind((local_addr, local_port))
548 # wait a while, retry
549 print >>sys.stderr, "%s: Could not bind. Retrying in a sec..." % (time.strftime('%c'),)
550 time.sleep(min(30.0,retrydelay))
553 rsock.bind((local_addr, local_port))
554 print >>sys.stderr, "Listening UDP at: %s:%d" % (local_addr, local_port)
555 print >>sys.stderr, "Connecting UDP to: %s:%d" % (peer_addr, peer_port)
556 rsock.connect((peer_addr, peer_port))
559 def udp_handshake(TERMINATE, rsock):
562 while not endme and not TERMINATE:
572 keepalive_thread = threading.Thread(target=keepalive)
573 keepalive_thread.start()
574 for i in xrange(900):
576 raise OSError, "Killed"
578 heartbeat = rsock.recv(10)
583 heartbeat = rsock.recv(10)
585 keepalive_thread.join()
587 def udp_establish(TERMINATE, local_addr, local_port, peer_addr, peer_port):
588 rsock = udp_connect(TERMINATE, local_addr, local_port, peer_addr,
590 udp_handshake(TERMINATE, rsock)
593 def tcp_connect(TERMINATE, stop, rsock, peer_addr, peer_port):
596 # The peer has a firewall that prevents a response to the connect, we
597 # will be forever blocked in the connect, so we put a reasonable timeout.
604 raise OSError, "Killed"
606 rsock.connect((peer_addr, peer_port))
610 # wait a while, retry
611 print >>sys.stderr, "%s: Could not connect. Retrying in a sec..." % (time.strftime('%c'),)
612 time.sleep(min(30.0,retrydelay))
615 rsock.connect((peer_addr, peer_port))
618 print >>sys.stderr, "tcp_connect: TCP sock connected to remote %s:%s" % (peer_addr, peer_port)
621 print >>sys.stderr, "tcp_connect: disabling NAGLE"
622 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
625 def tcp_listen(TERMINATE, stop, lsock, local_addr, local_port):
628 # We try to bind to the local virtual interface.
629 # It might not exist yet so we wait in a loop.
634 raise OSError, "Killed"
636 lsock.bind((local_addr, local_port))
639 # wait a while, retry
640 print >>sys.stderr, "%s: Could not bind. Retrying in a sec..." % (time.strftime('%c'),)
641 time.sleep(min(30.0,retrydelay))
644 lsock.bind((local_addr, local_port))
646 print >>sys.stderr, "tcp_listen: TCP sock listening in local sock %s:%s" % (local_addr, local_port)
647 # Now we wait until the other side connects.
648 # The other side might not be ready yet, so we also wait in a loop for timeouts.
653 raise OSError, "Killed"
654 rlist, wlist, xlist = select.select([lsock], [], [], timeout)
658 sock,raddr = lsock.accept()
659 print >>sys.stderr, "tcp_listen: TCP connection accepted in local sock %s:%s" % (local_addr, local_port)
664 def tcp_handshake(rsock, listen, hand):
665 # we are going to use a barrier algorithm to decide wich side listen.
666 # each side will "roll a dice" and send the resulting value to the other
672 peer_hand = rsock.recv(1)
673 print >>sys.stderr, "tcp_handshake: hand %s, peer_hand %s" % (hand, peer_hand)
677 elif hand > peer_hand:
680 except socket.timeout:
685 def tcp_establish(TERMINATE, local_addr, local_port, peer_addr, peer_port):
686 def listen(stop, hand, lsock, lresult):
688 rsock = tcp_listen(TERMINATE, stop, lsock, local_addr, local_port)
690 win = tcp_handshake(rsock, True, hand)
692 lresult.append((win, rsock))
694 def connect(stop, hand, rsock, rresult):
696 rsock = tcp_connect(TERMINATE, stop, rsock, peer_addr, peer_port)
698 win = tcp_handshake(rsock, False, hand)
700 rresult.append((win, rsock))
704 for i in xrange(0, 50):
708 raise OSError, "Killed"
709 hand = str(random.randint(1, 6))
713 lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
714 rsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
715 listen_thread = threading.Thread(target=listen, args=(stop, hand, lsock, lresult))
716 connect_thread = threading.Thread(target=connect, args=(stop, hand, rsock, rresult))
717 connect_thread.start()
718 listen_thread.start()
719 connect_thread.join()
721 (lwin, lrsock) = lresult[0]
722 (rwin, rrsock) = rresult[0]
723 if not lrsock or not rrsock:
729 # both socket are connected
739 raise OSError, "Error: tcp_establish could not establish connection."