I have this code that I am trying to use to connect three routers r1,r2,r3 together. I think I have to use switches to connect host nodes to the routers so each router is connected to a switch that is connected to a host. I have it working for 2 routers but I can't get it to work for three routers
I am using mininet to run the python script. Is there a way to add the ip addresses to the routing tables for the host. I am new to mininet so I am not familiar with connecting routers. I have to do this for 7 routers not just three but I am starting with 3 for now. Is there a better way to do this ?
#!/usr/bin/python
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import Node
from mininet.log import setLogLevel, info
from mininet.cli import CLI
class LinuxRouter(Node):
def config(self, **params):
super(LinuxRouter, self).config(**params)
self.cmd('sysctl net.ipv4.ip_forward=1')
def terminate(self):
self.cmd('sysctl net.ipv4.ip_forward=0')
super(LinuxRouter, self).terminate()
class NetworkTopo(Topo):
def build(self, **_opts):
# Add 2 routers in two different subnets
r1 = self.addHost('r1', cls=LinuxRouter, ip='10.0.0.1/24')
r2 = self.addHost('r2', cls=LinuxRouter, ip='10.1.0.1/24')
r3 = self.addHost('r3', cls=LinuxRouter, ip='10.2.0.1/24')
# Add 2 switches
s1 = self.addSwitch('s1')
s2 = self.addSwitch('s2')
s3 = self.addSwitch('s3')
# Add host-switch links in the same subnet
self.addLink(s1,
r1,
intfName2='r1-eth1',
params2={'ip': '10.0.0.1/24'})
self.addLink(s2,
r2,
intfName2='r2-eth1',
params2={'ip': '10.1.0.1/24'})
self.addLink(s3,
r3,
intfName2='r3-eth1',
params2={'ip': '10.2.0.1/24'})
# Add router-router link in a new subnet for the router-router connection
self.addLink(r1,
r2,
intfName1='r1-eth2',
intfName2='r2-eth2',
params1={'ip': '10.100.0.1/24'},
params2={'ip': '10.100.0.2/24'})
self.addLink(r1,
r2,
intfName1='r1-eth3',
intfName2='r2-eth3',
params1={'ip': '10.101.0.1/24'},
params2={'ip': '10.101.0.2/24'})
# Adding hosts specifying the default route
d1 = self.addHost(name='d1',
ip='10.0.0.251/24',
defaultRoute='via 10.0.0.1')
d2 = self.addHost(name='d2',
ip='10.1.0.252/24',
defaultRoute='via 10.1.0.1')
d3 = self.addHost(name='d3',
ip='10.1.0.253/24',
defaultRoute='via 10.1.0.1')
# Add host-switch links
self.addLink(d1, s1)
self.addLink(d2, s2)
self.addLink(d3, s2)
def run():
topo = NetworkTopo()
net = Mininet(topo=topo)
# Add routing for reaching networks that aren't directly connected
print info(net['r1'].cmd("ip route add 10.1.0.0/24 via 10.100.0.2 dev r1-eth2"))
print info(net['r2'].cmd("ip route add 10.0.0.0/24 via 10.100.0.1 dev r2-eth2"))
net.start()
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel('info')
run()
The reason why router 3 is not working is because you have not connected it! So instead of
self.addLink(r1,
r2,
intfName1='r1-eth3',
intfName2='r2-eth3',
params1={'ip': '10.101.0.1/24'},
params2={'ip': '10.101.0.2/24'})
Use
self.addLink(r1,
r2,
intfName1='r1-eth0',
intfName2='r3-eth0',
params1={'ip': '10.101.0.1/24'},
params2={'ip': '10.101.0.2/24'})
Related
I am having trouble connecting the switch to the controller in mininet. I use python script.
My script is the following.
The file name is test.py.
#!/usr/bin/python
from mininet.cli import CLI
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.node import Controller, OVSSwitch, RemoteController, OVSBridge
from mininet.log import setLogLevel
class test_Topo(Topo):
def build(self):
s1 = self.addSwitch( 's1')
s2 = self.addSwitch( 's2')
h1 = self.addHost( 'h1' )
h2 = self.addHost( 'h2' )
n1 = self.addHost( 'n1' )
self.addLink( s1, s2 )
self.addLink( s1, h1 )
self.addLink( s1, h2 )
self.addLink( s2, n1 )
def test():
topo = test_Topo()
net = Mininet(topo, build=False, waitConnected=True, switch=OVSSwitch, controller=Controller)
c0 = net.addController( 'c0', port=6633 )
c1 = net.addController('c1', port=6634)
net.build()
s1 = net.get('s1')
s2 = net.get('s2')
c0.start()
c1.start()
s1.start([c0])
s2.start([c1])
net.start()
net.pingAll()
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel('info')
test()
I want to have each switch connected to a different controller.
I ran the script with the following command.
sudo python3 test.py
The result is the following.
*** Creating network
*** Adding hosts:
h1 h2 n1
*** Adding switches:
s1 s2
*** Adding links:
(s1, h1) (s1, h2) (s1, s2) (s2, n1)
*** Configuring hosts
h1 h2 n1
*** Starting controller
c0 c1
*** Starting 2 switches
s1 s2 ...
*** Waiting for switches to connect
The connection does not end permanently after the message
*** Waiting for switches to connect
is displayed.
I referred to this code.
https://github.com/mininet/mininet/blob/master/examples/controllers.py
https://github.com/mininet/mininet/blob/master/examples/controllers2.py
I can't understand why switch can't connect the controller in my code.
I apologize for my poor English.
So I have 4 routers and 1 PC with 4 devices that connect to the closest router. So What I want to do is write a script in python that is running on the PC (Windows) and that PC is connected to 1 main router and that router connects to the other 3 routers.
1 PC -> Main Router (WiFi Enabled) -> 3 Other Routers (WiFi Enabled)
The bracelet (a WiFi enabled device) will connect to the nearest WiFi Router available of the 4 routers. I want to detect to which router is that bracelet connected to via a Python script.
I can make the Bracelet's IP Address Static as well but I was hoping to identify them using the MAC Address.
I can edit the routers configuration via web-page if needed.
Do ask for any clarifications if needed.
Hoping to hear soon.
Edit_1: Not to be confused with me asking for the whole code, I am in search of the right functions that can be used for this process and what are the possible configurations that I should set the router to.
Edit_2: Below is a sample code which allows for pinging IP's. So how can I get their MAC address (function) and also ping to other access points? I can alter properties of the routers.
import socket
from datetime import datetime
net = input("Enter the IP address: ") #e.g. is 192.168.18.1
net1 = net.split('.')
a = '.'
net2 = net1[0] + a + net1[1] + a + net1[2] + a
st1 = int(input("Enter the Starting Number: ")) #e.g. 1
en1 = int(input("Enter the Last Number: ")) #e.g. 10
en1 = en1 + 1
t1 = datetime.now()
def scan(addr):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socket.setdefaulttimeout(1)
result = s.connect_ex((addr,135))
if result == 0:
return 1
else :
return 0
def run1():
for ip in range(st1,en1):
addr = net2 + str(ip)
if (scan(addr)):
print (addr , "is live")
run1()
t2 = datetime.now()
total = t2 - t1
print ("Scanning completed in: " , total)
Edit_3: This searches out the MAC Address as well.
from scapy.all import ARP, Ether, srp
target_ip = "192.168.18.1/24"
# IP Address for the destination
# create ARP packet
arp = ARP(pdst=target_ip)
# create the Ether broadcast packet
# ff:ff:ff:ff:ff:ff MAC address indicates broadcasting
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
# stack them
packet = ether/arp
result = srp(packet, timeout=3, verbose=0)[0]
# a list of clients, we will fill this in the upcoming loop
clients = []
for sent, received in result:
# for each response, append ip and mac address to `clients` list
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
# print clients
print("Available devices in the network:")
print("IP" + " "*18+"MAC")
for client in clients:
print("{:16} {}".format(client['ip'], client['mac']))
if (client['mac'] == "f4:f5:e8:37:67:92"): #Testing mac address filter
print("Success")
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
...
I want to run instances of Quagga on each of my hosts in a Mininet setting. As implemented in the code below, I am able to mount /tmp/<host>/etc/quagga as /etc/quagga for each host, isolating configuration files inside the directory per host (private directories). But when I start Quagga service in each host (last lines in ipconf file below), they all share the same PID number, effectively creating the same process for all of them, although each one has its own Quagga configuration file.
I want to have separate Quagga instances, each with its own PID. How can I achieve this?
Custom topology file my_topo.py:
from mininet.topo import Topo
class my_topo(Topo):
"My custom topology settings"
def __init__(self, enable_all=True):
"Create custom topo."
Topo.__init__(self)
private_dirs = [("/etc/quagga", "/tmp/%(name)s/etc/quagga")]
h1 = self.addHost("h1",
ip="172.31.1.100/24",
privateDirs=private_dirs)
h2 = self.addHost("h2",
ip="172.31.2.100/24",
privateDirs=private_dirs)
h3 = self.addHost("h3",
ip="172.31.3.100/24",
privateDirs=private_dirs)
h4 = self.addHost("h4",
ip="172.31.4.100/24",
privateDirs=private_dirs)
h5 = self.addHost("h5",
ip="172.32.1.2/30",
privateDirs=private_dirs)
sA = self.addSwitch("s5")
sB = self.addSwitch("s6")
sC = self.addSwitch("s7")
sD = self.addSwitch("s8")
self.addLink(h1, sA)
self.addLink(h2, sB)
self.addLink(h3, sC)
self.addLink(h4, sD)
self.addLink(sA, sB)
self.addLink(sB, sD)
self.addLink(sD, sC)
self.addLink(sC, sA)
self.addLink(sA, sD)
self.addLink(h2, h5, 1, 0)
self.addLink(h4, h5, 1, 1)
topos = { "my_topo": ( lambda: my_topo() ) }
Commands file ipconf:
h1 /etc/init.d/quagga restart
h2 /etc/init.d/quagga restart
h3 /etc/init.d/quagga restart
h4 /etc/init.d/quagga restart
h5 /etc/init.d/quagga restart
Command to run Mininet:
sudo mn --custom mininet/custom/my_topo.py --topo=my_topo --controller=remote,ip=192.168.56.101,port=6633 --pre=ipconf
I figured out myself how to isolate processes from each host using Mininext, an expansion for Mininet which provides greater isolation between the hosts. Since Mininext is not compatible with recent versions of Mininet, I had to downgrade the latter to version 2.1.0, as instructed in the Mininext repository. Now I can run distinct Quagga instances in each host nicely.
Here is the adapted topology code using Mininext library, in case anyone faces the same situation:
import inspect
import os
from mininext.topo import Topo
from mininext.services.quagga import QuaggaService
from collections import namedtuple
QuaggaHost = namedtuple('QuaggaHost', 'name ip lo gw')
class my_topo(Topo):
'My custom topology settings'
def __init__(self):
Topo.__init__(self)
self_path = os.path.dirname(os.path.abspath(
inspect.getfile(inspect.currentframe())
))
quagga_svc = QuaggaService(autoStop=False)
quagga_base_config_path = self_path + '/configs/'
quagga_hosts = []
quagga_hosts.append(QuaggaHost(name='h1',
ip='172.31.1.100/24',
lo='10.0.1.1/24',
gw='gw 172.31.1.1'))
quagga_hosts.append(QuaggaHost(name='h2',
ip='172.31.2.100/24',
lo='10.0.2.1/24',
gw='gw 172.31.2.1'))
quagga_hosts.append(QuaggaHost(name='h3',
ip='172.31.3.100/24',
lo='10.0.3.1/24',
gw='gw 172.31.3.1'))
quagga_hosts.append(QuaggaHost(name='h4',
ip='172.31.4.100/24',
lo='10.0.4.1/24',
gw='gw 172.31.4.1'))
quagga_hosts.append(QuaggaHost(name='h5',
ip='172.32.1.2/30',
lo='10.0.5.1/24',
gw='gw 172.32.1.1'))
hosts = {}
for host in quagga_hosts:
quagga_container = self.addHost(name=host.name,
ip=host.ip,
defaultRoute=host.gw,
hostname=host.name,
privateLogDir=True,
privateRunDir=True,
inMountNamespace=True,
inPIDNamespace=True,
inUTSNamespace=True)
hosts[host.name] = quagga_container
self.addNodeLoopbackIntf(node=host.name, ip=host.lo)
quagga_svc_config = \
{'quaggaConfigPath': quagga_base_config_path + host.name}
self.addNodeService(node=host.name, service=quagga_svc,
nodeConfig=quagga_svc_config)
sA = self.addSwitch('s5')
sB = self.addSwitch('s6')
sC = self.addSwitch('s7')
sD = self.addSwitch('s8')
self.addLink(hosts['h1'], sA)
self.addLink(hosts['h2'], sB)
self.addLink(hosts['h3'], sC)
self.addLink(hosts['h4'], sD)
self.addLink(sA, sB)
self.addLink(sB, sD)
self.addLink(sD, sC)
self.addLink(sC, sA)
self.addLink(sA, sD)
self.addLink(hosts['h2'], hosts['h5'], 1, 0)
self.addLink(hosts['h4'], hosts['h5'], 1, 1)
topos = {'my_topo': (lambda: my_topo())}
Quagga configuration files must be placed inside configs directory, which lies in the same directory as the topology file. configs has directories for each host, as if each one was a /etc/quagga directory.
I'm writing a program which should detect a VPN traffic.
As far as I read about the subject, it seems the detection of the tunneling protocol is easy as firewall rules, using their dedicated ports:
PPTP: port 1723/TCP
OpenVPN: port 1194
L2TP: port 1701/UDP
My problem is with the SSTP, because it is using port 443, which is widely used.
So I have 2 questions:
Am I too naive to think I can detect those VPNs tunneling protocols only by their ports?
Does anyone has any idea how to detect SSTP and differ its traffic from any other type / app which uses TLS/SSL (even using DPI)?
I'm attaching piece of Python code which detects the communication in the above ports
import dpkt
import socket
# -------------------------- Globals
# VPN PORTS
import common
import dal
protocols_strs = {"pp2e_gre": "1723/TCP PP2P_GRE_PORT",
"openvpn": "1194 OPENVPN_PORT",
"ike": "500/UDP IKE_PORT",
"l2tp_ipsec": "1701/UDP L2TP_IPSEC_PORT"
}
port_protocols = {1723: 'pp2e_gre',
1194: 'openvpn',
500: 'ike',
1701: 'l2tp_ipsec'
}
# Dict of sets holding the protocols sessions
protocol_sessions = {"pp2e_gre": [],
"openvpn": [],
"ike": [],
"l2tp_ipsec": []}
# -------------------------- Functions
def is_bidirectional(five_tuple, protocol):
"""
Given a tuple and protocol check if the connection is bidirectional in the protocol
:param five_tuple:
:return: True of the connection is bidirectional False otherwise
"""
src_ip = five_tuple['src_ip']
dest_ip = five_tuple['dest_ip']
# Filter the sessions the five tuple's ips spoke in
ike_sessions = filter(lambda session: (session['src_ip'] == src_ip and session['dest_ip'] == dest_ip)
or
(session['dest_ip'] == src_ip and session['src_ip'] == dest_ip),
protocol_sessions[protocol])
# Return true if 2 session (1 for each direction) were found
return len(ike_sessions) == 2
def print_alert(timestamp, protocol, five_tuple):
"""
Print alert description to std
:param timestamp:
:param protocol:
:param five_tuple:
:return:
"""
print timestamp, ":\t detected port %s communication (%s:%s ---> %s:%s)" % \
(protocol, five_tuple['src_ip'], five_tuple['src_port'], five_tuple['dest_ip'],
five_tuple['dest_port'])
def pp2e_gre_openvpn_ike_handler(five_tuple):
# Get protocol
protocol = five_tuple['protocol']
# Clear old sessions in db
dal.remove_old_sessions(five_tuple['timestamp'], 'vpn_sessions')
# Clear old sessions in cache
protocol_sessions[protocol] = common.clear_old_sessions(five_tuple, protocol_sessions[protocol])
# If session already exists - return
if common.check_if_session_exists(five_tuple, protocol_sessions[protocol]):
session_to_update = common.get_session(five_tuple, protocol_sessions[protocol])
session_to_update['timestamp'] = five_tuple['timestamp']
return
# Update DB
dal.upsert_vpn_session(five_tuple)
# Add to cache
protocol_sessions[protocol].append(five_tuple)
# Print alert
print_alert(five_tuple['timestamp'], protocols_strs[protocol], five_tuple)
def l2tp_ipsec_handler(five_tuple):
if five_tuple in protocol_sessions['l2tp_ipsec']:
return
# If bi-directional IKE protocol performed earlier - alert
if not is_bidirectional(five_tuple, 'ike'):
return
protocol_sessions['l2tp_ipsec'].append(five_tuple)
print_alert(five_tuple['timestamp'], protocols_strs['l2tp_ipsec'], five_tuple)
# -------------------------- VPN ports jump tables
tcp_vpn_ports = {1723: pp2e_gre_openvpn_ike_handler,
1194: pp2e_gre_openvpn_ike_handler}
udp_vpn_ports = {500: pp2e_gre_openvpn_ike_handler,
1701: l2tp_ipsec_handler,
1194: pp2e_gre_openvpn_ike_handler}
# -------------------------- Functions
def process_packet(timestamp, packet):
"""
Given a packet process it for detecting a VPN communication
:param packet:
:param timestamp:
:return:
"""
# Parse the input
eth_frame = dpkt.ethernet.Ethernet(packet)
# Check if IP
if eth_frame.type != dpkt.ethernet.ETH_TYPE_IP:
return
# If not IP return
ip_frame = eth_frame.data
# if TCP or UDP
if ip_frame.p not in (dpkt.ip.IP_PROTO_TCP, dpkt.ip.IP_PROTO_UDP):
return
# Extract L3 frame
frame = ip_frame.data
# Extract ports
frame_ports = (frame.sport, frame.dport)
# get VPN ports in session
detected_ports = set(tcp_vpn_ports).intersection(frame_ports)
# If TCP VPN port was not detected return
if not detected_ports:
return
# Get detected port
port = detected_ports.pop()
# Translate port to str
protocol_str = port_protocols[port]
# Choose handler by port
handler = tcp_vpn_ports[port]
# Extract 5-tuple parameters from frames
five_tuple = {'src_ip': socket.inet_ntoa(ip_frame.src),
'dest_ip': socket.inet_ntoa(ip_frame.dst),
'src_port': frame.sport,
'dest_port': frame.dport,
'protocol': protocol_str,
'timestamp': timestamp}
# Invoke the chosen handler
handler(five_tuple)
"Am I too naive to think I can detect those VPNs tunneling protocols only by their ports?:
"The official OpenVPN port number is 1194, but any port number between 1 and 65535 will work. If you don't provide the 'port' option, 1194 will be used.
So if your code is looking for 1194 traffic, as per the dictionary entries, you will capture default Open VPN flows only.
The SSTP message is encrypted with the SSL channel of the HTTPS protocol. So I don't see how you would identify this traffic as it is encrypted. (Source)