# 網路模擬-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
===

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.

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.

> "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.


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

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**