User Tools

Site Tools


labs:ryu-lab-1-nat

RYU: Lab 1 Application NAT

Objet contrôleur RYU avec NAT
Niveau requis débutant, avisé
Débutant, à savoir ryu-overview
Suivi :DRAFT:

Objectif

Cette implémentation utilise Ryu NAT ( https://github.com/John-Lin/nat ) pour effectuer un comportement NAT afin de comprendre les opérations NAT.

Topologie expérimentale

Télécharger le code NAT depuis Github

$ git clone https://github.com/John-Lin/nat
$ cd nat

Initialiser les paramètres

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
  • Lancer Ryu NAT
$ ryu-manager base.py l2switch.py dhcp.py snat.py --verbose
  • Initialiser Ryu NAT

Cela initialisera la configuration NAT

curl --noproxy xx.xx.xxx.xxx -X POST -d '
{}' http://xx.xx.xxx.xxx:8383/api/nat_config_init

Lancer Ryu NAT

$ ryu-manager base.py l2switch.py dhcp.py snat.py --verbose

Mettre à jour les paramètres NAT

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

Expérimentation

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.

Analyse du code dans snat.py

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.

Activation de la section 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

labs/ryu-lab-1-nat.txt · Last modified: 2025/02/19 10:59 by 127.0.0.1