Objet | contrôleur RYU avec NAT |
---|---|
Niveau requis | débutant, avisé |
Débutant, à savoir | ryu-overview |
Suivi | :DRAFT: |
Cette implémentation utilise Ryu NAT ( https://github.com/John-Lin/nat ) pour effectuer un comportement NAT afin de comprendre les opérations NAT.
$ git clone https://github.com/John-Lin/nat $ cd nat
Avant d'iniliaser la configuration modifier les paramètres par défaut dans la méthode nat_config_init en fonction de l'environnement d'expérimentation dans snat.py
:
393 @route('nat_setings_init', urls.url_nat_config_init, methods='POST') 394 def nat_config_init(self, req, **kwargs): 395 save-dict = {} 396 397 # Default settings modify these value to fit your requirements 393 save_dict['wan_port'] = 1 399 save_dict['nat_public_ip'] = IPAddress('140.116.71.178') 400 save_dict['default_gateway'] = IPAddress('140.114.71.254') 401 402 network = '192.168.8.0/24' 403 save_dict['ip_network'] = IPNetwork(network) 404 save_dict['dhcp_gw_addr'] = IPNetwork(network)[1] 405 406 save_dict['broadcast_addr'] = IPAddress('192.168.8.255') 407 save_dict['dns_addr'] = IPAddress('8.8.8.8') 403 409 save_dict['dhcp_hw_addr'] = '08.00:27.8:0f:gd' 410 save_dict['MAC_ON_WAN'] = '00:0e:c6:67:ag:f6' 411 save_dict['MAC_ON_LAN'] = '00:0e:c6:87:ag:fa'
Wan_port | Cela correspond au port du commutateur et est défini sur le port externe au NAT. |
Nat_public_ip | NAT divulgué publiquement |
Default_gateway | L'adresse de passerelle du même domaine que l'adresse IP publique NAT |
Network | Domaine LAN dans NAT / 24 (plus masque) |
Ip_network | Domaine LAN dans NAT |
Dhcp_gw_addr | Cet auteur doit faire un dhcp simple, il y a donc une adresse de passerelle dhcp |
Broadcast_addr | Adresse de diffusion utilisée par dhcp |
Dns_addr | Adresse DNS |
Dhcp_hw_addr | adresse MAC Dhcp |
MAC_ON_WAN | adresse MAC WAN |
MAC_ON_LAN | adresse MAC LAN |
$ ryu-manager base.py l2switch.py dhcp.py snat.py --verbose
Cela initialisera la configuration NAT
curl --noproxy xx.xx.xxx.xxx -X POST -d ' {}' http://xx.xx.xxx.xxx:8383/api/nat_config_init
$ ryu-manager base.py l2switch.py dhcp.py snat.py --verbose
Méthode | PUT |
---|---|
URI | /api/nat_config_save |
Cela mettra à jour la configuration NAT
$ curl --noproxy xx.xx.xxx.xxx -X PUT -d ' { "wanPort": 4, "natPublicIp": "xx.xx.xxx.xxx", "defaultGateway": "xx.xx.xxx.x", "natPrivateNetwork": "192.168.8.0" }' http://xx.xx.xxx.xxx:8383/api/nat_config_save
Essayer d’exécuter les instructions Ping sur l’hôte 2 à partir de l’hôte 1.
Ping
H1:
$ ping 192.168.1.10
On peux voir que Ping ne peut pas passer.
Le traitement des paquets ICMP a été prévu mais qu'il n'a pas été implémenté:
292 @set_evcls (ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 293 def_packet_in_handler (self, ev). 294 msg = ev.msg 295 datapath = msg.datapath 296 # ofproto = datapath.ofproto 297 # parser = datapath.ofproto_parser 293 in_port = msg.match['rin_port'] 299 pkt = packet.Packet(msg.data) 300 301 pkt_ethernet = pkt_protocol(ethernet.ethernet) 302 pkt_arp = pkt.get_protocol(arp.arp) 303 # pkt_icmp = pkt.get_protoco(icmp.icmp) 304 pkt_ip = pkt.get_protocol(ipv4.ipv4) 305 pkt_tcp = pkt.get_protocol(tcp.tcp) 306 pkt_udp = pkt.get_protocol(udp.udp)
if pkt_tcp: # print "@@@ Install TCP Flow Entry @@@" tcp_src = pkt_tcp.src_port tcp_dst = pkt_tcp.dst_port match = parser.OFPMatch(in_port=in_port, eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_TCP, ipv4_src=ipv4_src, ipv4_dst=ipv4_dst, tcp_src=tcp_src, tcp_dst=tcp_dst) actions = [parser.OFPActionSetField(eth_dst=IP_TO_MAC_TABLE[target_ip]), parser.OFPActionSetField(ipv4_src=self.nat_public_ip), parser.OFPActionSetField(tcp_src=nat_port), parser.OFPActionOutput(out_port)] match_back = parser.OFPMatch(eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_TCP, ipv4_src=ipv4_dst, ipv4_dst=self.nat_public_ip, tcp_src=tcp_dst, tcp_dst=nat_port) actions_back = [parser.OFPActionSetField(eth_dst=eth_src), parser.OFPActionSetField(ipv4_dst=ipv4_src), parser.OFPActionSetField(tcp_dst=tcp_src), parser.OFPActionOutput(in_port)] elif pkt_udp: # print "@@@ Install UDP Flow Entry @@@" udp_src = pkt_udp.src_port udp_dst = pkt_udp.dst_port match = parser.OFPMatch(in_port=in_port, eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_UDP, ipv4_src=ipv4_src, ipv4_dst=ipv4_dst, udp_src=udp_src, udp_dst=udp_dst) actions = [parser.OFPActionSetField(eth_dst=IP_TO_MAC_TABLE[target_ip]), parser.OFPActionSetField(ipv4_src=self.nat_public_ip), parser.OFPActionSetField(udp_src=nat_port), parser.OFPActionOutput(out_port)] match_back = parser.OFPMatch(eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_UDP, ipv4_src=ipv4_dst, ipv4_dst=self.nat_public_ip, udp_src=udp_dst, udp_dst=nat_port) actions_back = [parser.OFPActionSetField(eth_dst=eth_src), parser.OFPActionSetField(ipv4_dst=ipv4_src), parser.OFPActionSetField(udp_dst=udp_src), parser.OFPActionOutput(in_port)] else: pass
Par conséquent, lorsque l'instruction Flow Entry est exécutée, il n'y a pas de partie ICMP. Pour faire passer la commande Ping efficacement, Il faut donc activer la résolution de la partie ICMP.
La première étape consiste donc à obtenir les informations d'en-tête ICMP en activant la prise en charge de protocole ICMP Pkt\_icmp = pkt.get\_protocol (icmp.icmp)
dans le code :
set_ev_cls(ofp_event.EventoFPPacketIn, MAIN_DISPATCHER) ef (self, ev), msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.matchr['in_port'] pkt = packet.Packet(msg.data) pkt_ethernet = pkt.get_protocol(ethernet.ethernet) pkt_arp = pkt.get_protoco/(arp.arp) Pkt_icmip= pkt.get_protocol(icmp.icmp) pkt_ip = pkt.get_protocol(ipv4.ipv4) pkt_tcp = pkt.get_protocol(tcp.tcp) pkt_udp = pkt.get_protocol(udp.udp)
Ensuite, lorsqu'on a déterminé qu'il s'agit d'un paquet ICMP, les instructions doivent être données au commutateur.
elif pkt_icmp: print "@@@ Install ICMP Flow Entry @@@" match = parser.OFPMatch(in_port=in_port, eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_ICMP, ipv4_src=ipv4_src, ipv4_dst=ipv4_dst, ) actions = [parser.OFPActionSetField(eth_dst=IP_TO_MAC_TABLE[target_ip]), parser.OFPActionSetField(ipv4_src=self.nat_public_ip), parser.OFPActionOutput(out_port)] match_back = parser.OFPMatch(eth_type=ether.ETH_TYPE_IP, ip_proto=inet.IPPROTO_ICMP, ipv4_src=ipv4_dst, ipv4_dst=self.nat_public_ip, ) actions_back = [parser.OFPActionSetField(eth_dst=eth_src), parser.OFPActionSetField(ipv4_dst=ipv4_src), parser.OFPActionOutput(in_port)] else: pass
Ensuite, il faut déterminer si l'adresse cible est dans ARP TABLE.
if pkt_tcp: if target_ip in IP_TO_MAC_TABLE: self._private_to-public(datapath=datapath, buffer_id=msg.buffer_id, data=msg.data, in_port=in_Port, out-port=self.wan_Port, pkt_ethernet=pkt_ethernet, pkt_ip=pkt_ip, pkt_tcp=pkt_tcp) elif pkt_udp: if target_ip in IP_TO_MAC_TABLE: self._private_to_public(datapath=datapath, buffer_id=msg.buffer_id, data=msg.data, in_port=in_Port, out-port=self.wan_Port, pkt_ethernet=pkt_ethernet, pkt_ip=pkt_ip, pkt_udp=pkt_udp) elif pkt_icmp: if target_ip in IP_TO_MAC_TABLE: self._private_to_public(datapath=datapath, buffer_id=msg.buffer_id, data=msg.data, in_port=in_Port, out-port=self.wan_Port, pkt_ethernet=pkt_ethernet, pkt_ip=pkt_ip, pkt_udp=pkt_icmp)
Relancer Ryu NAT
$ ryu-manager base.py l2switch.py dhcp.py snat.py --verbose
Essayer à nouveau d'utiliser la commande Ping de H1 à H2.
H1: $ ping 192.168.1.10
Peut être cette fois, cela passera