added simple_nat example
This commit is contained in:
77
examples/simple_nat/nat_app.py
Normal file
77
examples/simple_nat/nat_app.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# 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()
|
||||
Reference in New Issue
Block a user