2016-03-12 11:33:28 -08:00

78 lines
2.7 KiB
Python

# Copyright 2013-present Barefoot Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from scapy.all import *
import subprocess
import os
CLI_PATH = None
EXTERN_IP = "192.168.0.1"
current_nat_port = 1025
nat_mappings = {}
def send_to_CLI(cmd):
this_dir = os.path.dirname(os.path.realpath(__file__))
p = Popen(os.path.join(this_dir, 'sswitch_CLI.sh'), stdout=PIPE, stdin=PIPE)
output = p.communicate(input=cmd)[0]
# print output
# This is a very basic implementation of a full-cone NAT for TCP traffic
# We do not maintain a state machine for each connection, so we are not able to
# cleanup the port mappings, but this is sufficient for demonstration purposes
def process_cpu_pkt(p):
global current_nat_port
global EXTERN_IP
p_str = str(p)
# 0-7 : preamble
# 8 : device
# 9 : reason
# 10 : iface
# 11- : data packet (TCP)
if p_str[:8] != '\x00' * 8 or p_str[8] != '\x00' or p_str[9] != '\xab':
return
ip_hdr = None
tcp_hdr = None
try:
p2 = Ether(p_str[11:])
ip_hdr = p2['IP']
tcp_hdr = p2['TCP']
except:
return
print "Packet received"
print p2.summary()
if (ip_hdr.src, tcp_hdr.sport) not in nat_mappings:
ext_port = current_nat_port
current_nat_port += 1
print "Allocating external port", ext_port
nat_mappings[(ip_hdr.src, tcp_hdr.sport)] = ext_port
# internal to external rule for this mapping
send_to_CLI("table_add nat nat_hit_int_to_ext 0 1 1 %s&&&255.255.255.255 0.0.0.0&&&0.0.0.0 %d&&&0xffff 0&&&0 => %s %d 1" %\
(ip_hdr.src, tcp_hdr.sport, EXTERN_IP, ext_port))
# external to internal rule for this mapping
send_to_CLI("table_add nat nat_hit_ext_to_int 1 1 1 0.0.0.0&&&0.0.0.0 %s&&&255.255.255.255 0&&&0 %d&&&0xffff => %s %d 1" %\
(EXTERN_IP, ext_port, ip_hdr.src, tcp_hdr.sport))
# a little bit hacky, this essentially ensures that the packet we re-inject
# in the CPU iface will not be processed again by this method
new_p = p_str[:9] + '\xac' + p_str[10:]
sendp(new_p, iface="cpu-veth-0", verbose=0)
def main():
sniff(iface="cpu-veth-0", prn=lambda x: process_cpu_pkt(x))
if __name__ == '__main__':
main()