| 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