writing an ethernet bridge in python with scapy - python

I'd like to make something like this:
10.1.1.0/24 10.1.2.0/24
+------------+ +------------+ +------------+
| | | | | |
| | | | | |
| A d +-------+ e B f +-------+ g C |
| | | | | |
| | | | | |
+------------+ +------------+ +------------+
d e f g
10.1.1.1 10.1.1.2 10.1.2.1 10.1.2.2
So that Acan send packets to C through B.
I attempted to build this thing by running a scapy program on B that would sniff ports e and f, and in each case modify the destination IP and MAC address in the packet and then send it along through the other interface. Something like:
my_macs = [get_if_hwaddr(i) for i in get_if_list()]
pktcnt = 0
dest_mac_address = discover_mac_for_ip(dest_ip) #
output_mac = get_if_hwaddr(output_interface)
def process_packet(pkt):
# ignore packets that were sent from one of our own interfaces
if pkt[Ether].src in my_macs:
return
pktcnt += 1
p = pkt.copy()
# if this packet has an IP layer, change the dst field
# to our final destination
if IP in p:
p[IP].dst = dest_ip
# if this packet has an ethernet layer, change the dst field
# to our final destination. We have to worry about this since
# we're using sendp (rather than send) to send the packet. We
# also don't fiddle with it if it's a broadcast address.
if Ether in p \
and p[Ether].dst != 'ff:ff:ff:ff:ff:ff':
p[Ether].dst = dest_mac_address
p[Ether].src = output_mac
# use sendp to avoid ARP'ing and stuff
sendp(p, iface=output_interface)
sniff(iface=input_interface, prn=process_packet)
However, when I run this thing (full source here) all sorts of crazy things start to happen... Some of the packets get through, and I even get some responses (testing with ping) but there's some type of feedback loop that's causing a bunch of duplicate packets to get sent...
Any ideas what's going on here? Is it crazy to try to do this?
I'm kind of suspicious that the feedback loops are being caused by the fact that B is doing some processing of its own on the packets... Is there any way to prevent the OS from processing a packet after I've sniffed it?

IP packets bridging using scapy:
first make sure you have ip forwarding disabled otherwise duplicate packets will be noticed:
echo "0" > /proc/sys/net/ipv4/ip_forward <br>
second run the following python/scapy script:
!/usr/bin/python2
from optparse import OptionParser
from scapy.all import *
from threading import Thread
from struct import pack, unpack
from time import sleep
def sp_byte(val):
return pack("<B", val)
def su_nint(str):
return unpack(">I", str)[0]
def ipn2num(ipn):
"""ipn(etwork) is BE dotted string ip address
"""
if ipn.count(".") != 3:
print("ipn2num warning: string < %s > is not proper dotted IP address" % ipn)
return su_nint( "".join([sp_byte(int(p)) for p in ipn.strip().split(".")]))
def get_route_if(iface):
try:
return [route for route in conf.route.routes if route[3] == iface and route[2] == "0.0.0.0"][0]
except IndexError:
print("Interface '%s' has no ip address configured or link is down?" % (iface));
return None;
class PacketCapture(Thread):
def __init__(self, net, nm, recv_iface, send_iface):
Thread.__init__(self)
self.net = net
self.netmask = nm
self.recv_iface = recv_iface
self.send_iface = send_iface
self.recv_mac = get_if_hwaddr(recv_iface)
self.send_mac = get_if_hwaddr(send_iface)
self.filter = "ether dst %s and ip" % self.recv_mac
self.arp_cache = []
self.name = "PacketCapture(%s on %s)" % (self.name, self.recv_iface)
self.fw_count = 0
def run(self):
print("%s: waiting packets (%s) on interface %s" % (self.name, self.filter, self.recv_iface))
sniff(count = 0, prn = self.process, store = 0, filter = self.filter, iface = self.recv_iface)
def process(self, pkt):
# only bridge IP packets
if pkt.haslayer(Ether) and pkt.haslayer(IP):
dst_n = ipn2num(pkt[IP].dst)
if dst_n & self.netmask != self.net:
# don't forward if the destination ip address
# doesn't match the destination network address
return
# update layer 2 addresses
rmac = self.get_remote_mac(pkt[IP].dst)
if rmac == None:
print("%s: packet not forwarded %s %s -) %s %s" % (self.name, pkt[Ether].src, pkt[IP].src, pkt[Ether].dst, pkt[IP].dst))
return
pkt[Ether].src = self.send_mac
pkt[Ether].dst = rmac
#print("%s: forwarding %s %s -> %s %s" % (self.name, pkt[Ether].src, pkt[IP].src, pkt[Ether].dst, pkt[IP].dst))
sendp(pkt, iface = self.send_iface)
self.fw_count += 1
def get_remote_mac(self, ip):
mac = ""
for m in self.arp_cache:
if m["ip"] == ip and m["mac"]:
return m["mac"]
mac = getmacbyip(ip)
if mac == None:
print("%s: Could not resolve mac address for destination ip address %s" % (self.name, ip))
else:
self.arp_cache.append({"ip": ip, "mac": mac})
return mac
def stop(self):
Thread._Thread__stop(self)
print("%s stopped" % self.name)
if __name__ == "__main__":
parser = OptionParser(description = "Bridge packets", prog = "brscapy", usage = "Usage: brscapy -l <intf> (--left= <intf>) -r <inft> (--right=<intf>)")
parser.add_option("-l", "--left", action = "store", dest = "left", default = None, choices = get_if_list(), help = "Left side network interface of the bridge")
parser.add_option("-r", "--right", action = "store", dest = "right", default = None, choices = get_if_list(), help = "Right side network interface of the bridge")
args, opts = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
lif = args.left
rif = args.right
lroute = get_route_if(lif)
rroute = get_route_if(rif)
if (lroute == None or rroute == None):
print("Invalid ip addressing on given interfaces");
exit(1)
if (len(lroute) != 5 or len(rroute) != 5):
print("Invalid scapy routes")
exit(1)
conf.verb = 0
lthread = PacketCapture(rroute[0], rroute[1], lif, rif)
rthread = PacketCapture(lroute[0], lroute[1], rif, lif)
lthread.start()
rthread.start()
try:
while True:
sys.stdout.write("FORWARD count: [%s -> %s %d] [%s <- %s %d]\r" % (lif, rif, lthread.fw_count, lif, rif, rthread.fw_count))
sys.stdout.flush()
sleep(0.1)
except KeyboardInterrupt:
pass
lthread.stop()
rthread.stop()
lthread.join()
rthread.join()
On my pc:
# ./brscapy.py --help
Usage: brscapy -l <intf> (--left= <intf>) -r <inft> (--right=<intf>)
Bridge packets
Options:
-h, --help show this help message and exit
-l LEFT, --left=LEFT Left side network interface of the bridge
-r RIGHT, --right=RIGHT
Right side network interface of the bridge
# ./brscapy.py -l e0 -r e2
PacketCapture(Thread-1 on e0): waiting packets (ether dst 00:16:41:ea:ff:dc and ip) on interface e0
PacketCapture(Thread-2 on e2): waiting packets (ether dst 00:0d:88:cc:ed:15 and ip) on interface e2
FORWARD count: [e0 -> e2 5] [e0 <- e2 5]

It is kinda crazy to do this, but it's not a bad way to spend your time. You'll learn a bunch of interesting stuff. However you might want to think about hooking the packets a little lower - I don't think scapy is capable of actually intercepting packets - all libpcap does is set you promisc and let you see everything, so you and the kernel are both getting the same stuff. If you're turning around and resending it, thats likely the cause of your packet storm.
However, you could set up some creative firewall rules that partition each interface off from each-other and hand the packets around that way, or use something like divert sockets to actually thieve the packets away from the kernel so you can have your way with them.

Related

How to send and receive CAN messages between 2 Linux machines without any CAN hardware?

I have been trying to establish CAN communication between my laptop (Ubuntu 20 Virtualbox) and Raspberry Pi (Ubuntu 20) without any CAN hardware, because that will not get the CAN message in the simulation environment. I want to send the CAN data as payload through wifi or USB. Then my python simulation environment should be able to interpret these as CAN messages and forward appropriately.
I have tried vcan from socketcan but it works only between 2 terminals of the same Linux machine. I have been advised to look at slcan. It seems like there is no other option other than using actual CAN hardware. I can't find any tutorial or any other help anywhere.
I will humbly appreciate if anyone can suggest how to send and receive CAN messages between 2 Linux machines without any CAN hardware through wifi or USB?
Python source code I tried:
import sys
import socket
import argparse
import struct
import errno
class CANSocket(object):
FORMAT = "<IB3x8s"
FD_FORMAT = "<IB3x64s"
CAN_RAW_FD_FRAMES = 5
def __init__(self, interface=None):
self.sock = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
if interface is not None:
self.bind(interface)
def bind(self, interface):
self.sock.bind((interface,))
self.sock.setsockopt(socket.SOL_CAN_RAW, self.CAN_RAW_FD_FRAMES, 1)
def send(self, cob_id, data, flags=0):
cob_id = cob_id | flags
can_pkt = struct.pack(self.FORMAT, cob_id, len(data), data)
self.sock.send(can_pkt)
def recv(self, flags=0):
can_pkt = self.sock.recv(72)
if len(can_pkt) == 16:
cob_id, length, data = struct.unpack(self.FORMAT, can_pkt)
else:
cob_id, length, data = struct.unpack(self.FD_FORMAT, can_pkt)
cob_id &= socket.CAN_EFF_MASK
return (cob_id, data[:length])
def format_data(data):
return ''.join([hex(byte)[2:] for byte in data])
def generate_bytes(hex_string):
if len(hex_string) % 2 != 0:
hex_string = "0" + hex_string
int_array = []
for i in range(0, len(hex_string), 2):
int_array.append(int(hex_string[i:i+2], 16))
return bytes(int_array)
def send_cmd(args):
try:
s = CANSocket(args.interface)
except OSError as e:
sys.stderr.write('Could not send on interface {0}\n'.format(args.interface))
sys.exit(e.errno)
try:
cob_id = int(args.cob_id, 16)
except ValueError:
sys.stderr.write('Invalid cob-id {0}\n'.format(args.cob_id))
sys.exit(errno.EINVAL)
s.send(cob_id, generate_bytes(args.body), socket.CAN_EFF_FLAG if args.extended_id else 0)
def listen_cmd(args):
try:
s = CANSocket(args.interface)
except OSError as e:
sys.stderr.write('Could not listen on interface {0}\n'.format(args.interface))
sys.exit(e.errno)
print('Listening on {0}'.format(args.interface))
while True:
cob_id, data = s.recv()
print('%s %03x#%s' % (args.interface, cob_id, format_data(data)))
def parse_args():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
send_parser = subparsers.add_parser('send', help='send a CAN packet')
send_parser.add_argument('interface', type=str, help='interface name (e.g. vcan0)')
send_parser.add_argument('cob_id', type=str, help='hexadecimal COB-ID (e.g. 10a)')
send_parser.add_argument('body', type=str, nargs='?', default='',
help='hexadecimal msg body up to 8 bytes long (e.g. 00af0142fe)')
send_parser.add_argument('-e', '--extended-id', action='store_true', default=False,
help='use extended (29 bit) COB-ID')
send_parser.set_defaults(func=send_cmd)
listen_parser = subparsers.add_parser('listen', help='listen for and print CAN packets')
listen_parser.add_argument('interface', type=str, help='interface name (e.g. vcan0)')
listen_parser.set_defaults(func=listen_cmd)
return parser.parse_args()
def main():
args = parse_args()
args.func(args)
if __name__ == '__main__':
main()
CAN is a broadcast protocol and not a connection protocol like TCP or datagram protocol like UDP. However, ff you want abstract the hardware but still simulate the higher layer behaviour of CAN, I'd suggest the best way to do would be with UDP (but TCP as suggested by #M. Spiller also works, just means handling accepting connections which you don't have to bother with for UDP), and send and receive packets with a byte structure the same as a CAN frame. You would also need to account for filters and error frames.
If you're going to use socketcan on linux, your UDP packets should look like:
struct {
uint16_t id; /* CAN ID of the frame */
uint8_t dlc; /* frame payload length in bytes */
uint8_t data[8]; /* CAN frame payload */
} simulated_udp_can_frame;
You should read the socketCAN kernel documentation for more detail.

Network Scanner build using Scapy only scans itself

Below is the code of NetworkScanner that I tried to build as my first Python project.
#!/usr/bin/env python
import scapy.all as scapy
import optparse
def scan(ip):
packet1 = scapy.ARP(pdst=ip)
etherpacket = scapy.Ether(dst='ff:ff:ff:ff:ff:ff')
broadcast_packet = etherpacket / packet1
ans = scapy.srp(broadcast_packet, timeout=60, verbose=False)[0]
ret_list = list()
for item in ans:
dic = {}
dic['ip'] = item[1].pdst
dic['mac'] = item[1].hwdst
ret_list.append(dic)
print(ret_list)
return ret_list
def printfun(returnlist):
print("IP\t\t\tMAC Address\n----------------------------------------------")
for elem in returnlist:
print(elem["ip"] + "\t\t" + elem["mac"])
def getip():
parser = optparse.OptionParser()
parser.add_option('-i', "--ip", dest = 'received_ip', help="Please enter the ip you want to scan")
(option, arguments) = parser.parse_args()
return option.received_ip
ip = getip()
if ip:
result = scan(ip)
printfun(result)
else:
print("no ip given")
Now I did follow some tutorials and learned to build parallelly and it seems right to me but I am not good.
but when I execute the program, it only scans the IP of virtual Host itself on which it is executed.
/PycharmProjects/Networkscanner$ sudo python networkscanner.py -i 192.168.1.1/24
[{'ip': '192.168.1.205', 'mac': '08:00:27:1f:30:76'}, {'ip': '192.168.1.205', 'mac': '08:00:27:1f:30:76'}]
IP MAC Address
----------------------------------------------
192.168.1.205 08:00:27:1f:30:76
192.168.1.205 08:00:27:1f:30:76
when I use the inbuild network scanner of python it gives these results.
Currently scanning: Finished! | Screen View: Unique Hosts
5 Captured ARP Req/Rep packets, from 4 hosts. Total size: 300
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
-----------------------------------------------------------------------------
192.168.1.1 a0:47:d7:36:2a:c0 2 120 Best IT World (India) Pvt Lt
192.168.1.203 e4:42:a6:30:93:64 1 60 Intel Corporate
192.168.1.205 30:b5:c2:10:05:3b 1 60 TP-LINK TECHNOLOGIES CO.,LTD
192.168.1.207 30:b5:c2:10:05:3b 1 60 TP-LINK TECHNOLOGIES CO.,LTD
Edit:
I tried the Monitor mode, but that does not help.
I also tried to run it on main windows with also an external WiFi adaptor, still same issue
can someone please assist what is wrong in my code?
Determining the problem
If we name variables more appropriately, it becomes apparent what the problem is:
for sent_recv in ans:
dic = {}
return_packet = sent_recv[1]
dic['ip'] = return_packet.pdst
dic['mac'] = return_packet.hwdst
ret_list.append(dic)
Each item is a tuple of a sent packet and a received packet. Naming it as such helps to identify it.
The 2nd element of sent_recv is the returned packet. Let's name it as such.
The destination IP and MAC address of the returning packet are going to be that of our machine. This makes sense in the context of your output: You get your own IP/MAC for every response.
So if we change it to the src IP/MAC of the returning packet, we'll get the information we're after:
for sent_recv in ans:
dic = {}
return_packet = sent_recv[1]
# Difference is dst => src here
dic['ip'] = return_packet.psrc
dic['mac'] = return_packet.hwsrc
ret_list.append(dic)
Note: An ARP packet should not take 60s to return - it's more on the scale of 10-100ms depending on network size. A timeout of 2s is more appropriate here.
Testing the fix
Running this with modified code, we get the desired result:
$ python script.py -i "192.168.1.0/24"
[{'ip': '192.168.1.48', 'mac': '00:1b:78:20:ee:40'},
{'ip': '192.168.1.67', 'mac': '6c:33:a9:42:6a:18'},
...
IP MAC Address
----------------------------------------------
192.168.1.48 00:1b:78:20:ee:40
192.168.1.67 6c:33:a9:42:6a:18
...

Python: what exactly does .payload in scapy?

I'm trying to understand a Python script that analyzes beacon frames. But I'm stuck at something called .payload. Looking at the Python documentation and doing research didn't help me out. I found out that the payload is the data carried by the frame.
def insert_ap(pkt):
## Done in the lfilter param
# if Dot11Beacon not in pkt and Dot11ProbeResp not in pkt:
# return
bssid = pkt[Dot11].addr3
if bssid in aps:
return
p = pkt[Dot11Elt]
cap = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}"
"{Dot11ProbeResp:%Dot11ProbeResp.cap%}").split('+')
ssid, channel = None, None
crypto = set()
while isinstance(p, Dot11Elt):
if p.ID == 0:
ssid = p.info
elif p.ID == 3:
channel = ord(p.info)
elif p.ID == 48:
crypto.add("WPA2")
elif p.ID == 221 and p.info.startswith('\x00P\xf2\x01\x01\x00'):
crypto.add("WPA")
p = p.payload # HERE IT IS
if not crypto:
if 'privacy' in cap:
crypto.add("WEP")
else:
crypto.add("OPN")
print "NEW AP: %r [%s], channed %d, %s" % (ssid, bssid, channel,
' / '.join(crypto))
aps[bssid] = (ssid, channel, crypto)
aps = {}
sniff(iface='mon0', prn=insert_ap, store=False,
lfilter=lambda p: (Dot11Beacon in p or Dot11ProbeResp in p))
The payload function is written in a while loop. The loop is active as long as the packet is an instance of Dot11Elt. But what does .payload do that it's no longer Dot11Elt (?)
Thank you!
packet.payload is just a pointer to the next layer.
Take a look at the Scapy documentation.
For example, if pkt were constructed as such:
pkt = Dot11()/foo()/IP()/TCP()
In your example, p is initially set to pkt[Dot11]. Therefore, p.payload is pkt[Dot11].payload, which points to the foo object. At the end of the loop, p is advanced to p.payload. As long as p is of type Dot11Elt, the loop will keep running.
If we assume that both Dot11, and foo are of type Dot11Elt, then the loop will run until p is pointing to the IP layer.

POX in mininet: What does event.parsed give in pox? What is parse.next?

In l3_learning.py, there is a method in class l3_switch named _handle_PacketIn.
Now I understand that this event is when a switch contacts controller when it receives a packet corresponding to which it has no entries in its table.
What I don't understand is that here
packet = event.parsed
Now what does packet.next mean in isinstance(packet.next, ipv4)?
def _handle_PacketIn (self, event):
dpid = event.connection.dpid
inport = event.port
packet = event.parsed
if not packet.parsed:
log.warning("%i %i ignoring unparsed packet", dpid, inport)
return
if dpid not in self.arpTable:
# New switch -- create an empty table
self.arpTable[dpid] = {}
for fake in self.fakeways:
self.arpTable[dpid][IPAddr(fake)] = Entry(of.OFPP_NONE,
dpid_to_mac(dpid))
if packet.type == ethernet.LLDP_TYPE:
# Ignore LLDP packets
return
if isinstance(packet.next, ipv4):
log.debug("%i %i IP %s => %s", dpid,inport,
packet.next.srcip,packet.next.dstip)
# Send any waiting packets...
self._send_lost_buffers(dpid, packet.next.srcip, packet.src, inport)
# Learn or update port/MAC info
if packet.next.srcip in self.arpTable[dpid]:
if self.arpTable[dpid][packet.next.srcip] != (inport, packet.src):
log.info("%i %i RE-learned %s", dpid,inport,packet.next.srcip)
else:
log.debug("%i %i learned %s", dpid,inport,str(packet.next.srcip))
self.arpTable[dpid][packet.next.srcip] = Entry(inport, packet.src)
# Try to forward
dstaddr = packet.next.dstip
if dstaddr in self.arpTable[dpid]:
# We have info about what port to send it out on...
prt = self.arpTable[dpid][dstaddr].port
mac = self.arpTable[dpid][dstaddr].mac
I think I have figured it out.
packet is entire packet that data-link layer sends to the physical layer. packet.next removes the encapsulation of data-link layer and reveals the IP packet (the packet sent by IP layer to data-link layer). So to get the source MAC address we use packet.src and to get the IP address of the source we use packet.next.srcip

Alternative to tuntap

I'm trying to transmit TCP/IP over a radio that is connected to my computer (specifically, the USRP). Right now, it's done very simply using Tun/Tap to set up a new network interface. Here's the code:
from gnuradio import gr, gru, modulation_utils
from gnuradio import usrp
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import random
import time
import struct
import sys
import os
# from current dir
from transmit_path import transmit_path
from receive_path import receive_path
import fusb_options
#print os.getpid()
#raw_input('Attach and press enter')
# Linux specific...
# TUNSETIFF ifr flags from <linux/tun_if.h>
IFF_TUN = 0x0001 # tunnel IP packets
IFF_TAP = 0x0002 # tunnel ethernet frames
IFF_NO_PI = 0x1000 # don't pass extra packet info
IFF_ONE_QUEUE = 0x2000 # beats me ;)
def open_tun_interface(tun_device_filename):
from fcntl import ioctl
mode = IFF_TAP | IFF_NO_PI
TUNSETIFF = 0x400454ca
tun = os.open(tun_device_filename, os.O_RDWR)
ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode))
ifname = ifs[:16].strip("\x00")
return (tun, ifname)
# /////////////////////////////////////////////////////////////////////////////
# the flow graph
# /////////////////////////////////////////////////////////////////////////////
class my_top_block(gr.top_block):
def __init__(self, mod_class, demod_class,
rx_callback, options):
gr.top_block.__init__(self)
self.txpath = transmit_path(mod_class, options)
self.rxpath = receive_path(demod_class, rx_callback, options)
self.connect(self.txpath);
self.connect(self.rxpath);
def send_pkt(self, payload='', eof=False):
return self.txpath.send_pkt(payload, eof)
def carrier_sensed(self):
"""
Return True if the receive path thinks there's carrier
"""
return self.rxpath.carrier_sensed()
# /////////////////////////////////////////////////////////////////////////////
# Carrier Sense MAC
# /////////////////////////////////////////////////////////////////////////////
class cs_mac(object):
"""
Prototype carrier sense MAC
Reads packets from the TUN/TAP interface, and sends them to the PHY.
Receives packets from the PHY via phy_rx_callback, and sends them
into the TUN/TAP interface.
Of course, we're not restricted to getting packets via TUN/TAP, this
is just an example.
"""
def __init__(self, tun_fd, verbose=False):
self.tun_fd = tun_fd # file descriptor for TUN/TAP interface
self.verbose = verbose
self.tb = None # top block (access to PHY)
def set_top_block(self, tb):
self.tb = tb
def phy_rx_callback(self, ok, payload):
"""
Invoked by thread associated with PHY to pass received packet up.
#param ok: bool indicating whether payload CRC was OK
#param payload: contents of the packet (string)
"""
if self.verbose:
print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload))
if ok:
os.write(self.tun_fd, payload)
def main_loop(self):
"""
Main loop for MAC.
Only returns if we get an error reading from TUN.
FIXME: may want to check for EINTR and EAGAIN and reissue read
"""
min_delay = 0.001 # seconds
while 1:
payload = os.read(self.tun_fd, 10*1024)
if not payload:
self.tb.send_pkt(eof=True)
break
if self.verbose:
print "Tx: len(payload) = %4d" % (len(payload),)
delay = min_delay
while self.tb.carrier_sensed():
sys.stderr.write('B')
time.sleep(delay)
if delay < 0.050:
delay = delay * 2 # exponential back-off
self.tb.send_pkt(payload)
# /////////////////////////////////////////////////////////////////////////////
# main
# /////////////////////////////////////////////////////////////////////////////
def main():
mods = modulation_utils.type_1_mods()
demods = modulation_utils.type_1_demods()
parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
expert_grp = parser.add_option_group("Expert")
parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
default='gmsk',
help="Select modulation from: %s [default=%%default]"
% (', '.join(mods.keys()),))
parser.add_option("-v","--verbose", action="store_true", default=False)
expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30,
help="set carrier detect threshold (dB) [default=%default]")
expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun",
help="path to tun device file [default=%default]")
transmit_path.add_options(parser, expert_grp)
receive_path.add_options(parser, expert_grp)
for mod in mods.values():
mod.add_options(expert_grp)
for demod in demods.values():
demod.add_options(expert_grp)
fusb_options.add_options(expert_grp)
(options, args) = parser.parse_args ()
if len(args) != 0:
parser.print_help(sys.stderr)
sys.exit(1)
if options.rx_freq is None or options.tx_freq is None:
sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
parser.print_help(sys.stderr)
sys.exit(1)
# open the TUN/TAP interface
(tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename)
# Attempt to enable realtime scheduling
r = gr.enable_realtime_scheduling()
if r == gr.RT_OK:
realtime = True
else:
realtime = False
print "Note: failed to enable realtime scheduling"
# If the user hasn't set the fusb_* parameters on the command line,
# pick some values that will reduce latency.
if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
if realtime: # be more aggressive
options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
else:
options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16)
#print "fusb_block_size =", options.fusb_block_size
#print "fusb_nblocks =", options.fusb_nblocks
# instantiate the MAC
mac = cs_mac(tun_fd, verbose=True)
# build the graph (PHY)
tb = my_top_block(mods[options.modulation],
demods[options.modulation],
mac.phy_rx_callback,
options)
mac.set_top_block(tb) # give the MAC a handle for the PHY
if tb.txpath.bitrate() != tb.rxpath.bitrate():
print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % (
eng_notation.num_to_str(tb.txpath.bitrate()),
eng_notation.num_to_str(tb.rxpath.bitrate()))
print "modulation: %s" % (options.modulation,)
print "freq: %s" % (eng_notation.num_to_str(options.tx_freq))
print "bitrate: %sb/sec" % (eng_notation.num_to_str(tb.txpath.bitrate()),)
print "samples/symbol: %3d" % (tb.txpath.samples_per_symbol(),)
#print "interp: %3d" % (tb.txpath.interp(),)
#print "decim: %3d" % (tb.rxpath.decim(),)
tb.rxpath.set_carrier_threshold(options.carrier_threshold)
print "Carrier sense threshold:", options.carrier_threshold, "dB"
print
print "Allocated virtual ethernet interface: %s" % (tun_ifname,)
print "You must now use ifconfig to set its IP address. E.g.,"
print
print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,)
print
print "Be sure to use a different address in the same subnet for each machine."
print
tb.start() # Start executing the flow graph (runs in separate threads)
mac.main_loop() # don't expect this to return...
tb.stop() # but if it does, tell flow graph to stop.
tb.wait() # wait for it to finish
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
(Anyone familiar with GNU Radio will recognize this as tunnel.py)
My question is, is there a better way to move packets to and from the kernel than tun/tap? I've been looking at ipip or maybe using sockets, but I'm pretty sure those won't be very fast. Speed is what I'm most concerned with.
Remember that tunnel.py is a really, really rough example, and hasn't been updated in a while. It's not really meant to be a basis for other code, so be careful of how much you rely on the code.
Also, remember that TCP over unreliable radio links has significant issues:
http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_over_wireless_networks

Categories