---
# System prepended metadata

title: 網路模擬-Reflector
tags: [scapy, P4, Mininet]

---

# 網路模擬-Reflector

###### tags: `P4`、`Mininet`、`scapy`
-------

Question
===

- In this environment, we need to prepare a host and switch, you can check [nsg-ethz](https://github.com/nsg-ethz/p4-learning/tree/master/examples/reflector) to build this environment.

Environment
===

![](https://i.imgur.com/peYwF48.png)

Codes
===

> p4app.json ↓
```
{
  "program": "reflector.p4",
  "switch": "simple_switch",
  "compiler": "p4c",
  "options": "--target bmv2 --arch v1model --std p4-16",
  "switch_cli": "simple_switch_CLI",
  "cli": true,
  "pcap_dump": true,
  "enable_log": true,
  "topo_module": {
    "file_path": "",
    "module_name": "p4utils.mininetlib.apptopo",
    "object_name": "AppTopo"
  },
  "controller_module": null,
  "topodb_module": {
    "file_path": "",
    "module_name": "p4utils.utils.topology",
    "object_name": "Topology"
  },
  "mininet_module": {
    "file_path": "",
    "module_name": "p4utils.mininetlib.p4net",
    "object_name": "P4Mininet"
  },
  "topology": {
    "links": [["h1", "s1"]],
    "hosts": {
      "h1": {
      }
    },
    "switches": {
      "s1": {
        "program": "reflector.p4"
      }
    }
  }
}
```

> reflector.p4 ↓
```
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

/*************************************************************************
*********************** H E A D E R S  ***********************************
*************************************************************************/

typedef bit<48> macAddr_t;

header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16>   etherType;
}

struct metadata {
    /* empty */
}

struct headers {
    ethernet_t   ethernet;
}

/*************************************************************************
*********************** P A R S E R  ***********************************
*************************************************************************/

parser MyParser(packet_in packet,
                out headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {

      state start{
  	  packet.extract(hdr.ethernet);
          transition accept;
      }

}

/*************************************************************************
************   C H E C K S U M    V E R I F I C A T I O N   *************
*************************************************************************/

control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply {  }
}


/*************************************************************************
**************  I N G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

control MyIngress(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {

    action swap_mac(){
       macAddr_t tmp;
	   tmp = hdr.ethernet.srcAddr;
	   hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
	   hdr.ethernet.dstAddr = tmp;
    }

    apply {
       // Swap MAC addresses.
       swap_mac();

       //Set Output port == Input port
       standard_metadata.egress_spec = standard_metadata.ingress_port;
    }
}

/*************************************************************************
****************  E G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    apply {  }
}

/*************************************************************************
*************   C H E C K S U M    C O M P U T A T I O N   **************
*************************************************************************/

control MyComputeChecksum(inout headers  hdr, inout metadata meta) {
    apply { }
}

/*************************************************************************
***********************  D E P A R S E R  *******************************
*************************************************************************/

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
		// parsed headers have to be added again into the packet
		packet.emit(hdr.ethernet);
	}
}

/*************************************************************************
***********************  S W I T C H  *******************************
*************************************************************************/

V1Switch(
	MyParser(),
	MyVerifyChecksum(),
	MyIngress(),
	MyEgress(),
	MyComputeChecksum(),
	MyDeparser()
) main;
```

> send_receive.py ↓
```
#!/usr/bin/env python
import sys
import socket
import random
import time
from threading import Thread, Event
from scapy.all import *


class Sniffer(Thread):
    def __init__(self, interface="eth0"):
        super(Sniffer, self).__init__()

        self.interface = interface
        self.my_mac = get_if_hwaddr(interface)
        self.daemon = True

        self.socket = None
        self.stop_sniffer = Event()

    def isNotOutgoing(self, pkt):
        return pkt[Ether].src != self.my_mac

    def run(self):
        self.socket = conf.L2listen(
            type=ETH_P_ALL,
            iface=self.interface,
            filter="ip"
        )
        sniff(opened_socket=self.socket, prn=self.print_packet, lfilter=self.isNotOutgoing,
              stop_filter=self.should_stop_sniffer)

    def join(self, timeout=None):
        self.stop_sniffer.set()
        super(Sniffer, self).join(timeout)

    def should_stop_sniffer(self, packet):
        return self.stop_sniffer.isSet()

    def print_packet(self, packet):
        print "[!] A packet was reflected from the switch: "
        # packet.show()
        ether_layer = packet.getlayer(Ether)
        print("[!] Info: {src} -> {dst}\n".format(src=ether_layer.src, dst=ether_layer.dst))


def get_if():
    ifs = get_if_list()
    iface = None  # "h1-eth0"
    for i in get_if_list():
        if "eth0" in i:
            iface = i
            break;
    if not iface:
        print "Cannot find eth0 interface"
        exit(1)
    return iface


def send_packet(iface, addr):
    raw_input("Press the return key to send a packet:")
    print "Sending on interface %s to %s\n" % (iface, str(addr))
    pkt = Ether(src=get_if_hwaddr(iface), dst='00:01:02:03:04:05')
    pkt = pkt / IP(dst=addr)
    sendp(pkt, iface=iface, verbose=False)


def main():
    addr = "10.0.0.2"
    addr = socket.gethostbyname(addr)
    iface = get_if()

    listener = Sniffer(iface)
    listener.start()
    time.sleep(0.1)

    try:
        while True:
            send_packet(iface, addr)
            time.sleep(0.5)

    except KeyboardInterrupt:
        print("[*] Stop sniffing")
        listener.join(2.0)

        if listener.isAlive():
            listener.socket.close()


if __name__ == '__main__':
    main()
```

Test
===

> use "p4run" to connect the p4 environment.

> using "xterm h1" to open terminal for h1, we need to type twice. one type "wireshark" to check the packet, another type "scapy".
> if you type "scapy" and something error, it might be not install, just using "pip install scapy" to fix error.

![](https://i.imgur.com/tH6wHVR.jpg)


For scapy, we can follow [Sending & recieving packets](https://0xbharath.github.io/art-of-packet-crafting-with-scapy/scapy/sending_recieving/index.html) this website to know more scapy's command and detail.

> follow in this web, we can type "pkt=Ether()/IP()/UDP()" to build the packet model.
>
> "pkt.show()" can show packet information.

![](https://i.imgur.com/OaJc0js.jpg)

> "pkt=Ether(dst="MAC address")/IP(dst="ip address")/UDP(dport=,sport=)", the packet dst you can put what you want, e.g. "pkt=Ether(dst="01:02:03:04:05:06")/IP(dst="10.0.0.1")/UDP(dport=1,sport=1)".
>
> don't forget to using "pkt.show()" to check packet info.

![](https://i.imgur.com/LGcNfqA.jpg)

![](https://i.imgur.com/xdMblSh.jpg)

send packet command you can use "sendp(pkt,iface="h1-eth0")" and check wireshark.

![](https://i.imgur.com/0t4TNrV.jpg)

done.

Reference
===
 1.pkt_reflector,source:https://github.com/nsg-ethz/p4-learning/tree/master/examples/reflector
 
 2.sending and receive,source:https://0xbharath.github.io/art-of-packet-crafting-with-scapy/scapy/sending_recieving/index.html
 
---
###### 2020-05-25
###### written by **yi-hao tu**