I currently have two hosts which run a client and server Python program which send TLS traffic to one another - I have tested this outside of mininet to confirm it works (and it does!).
However, the goal here is to use tcpdump/tshark/wireshark to capture the TLS traffic between these two hosts. I have tried things such as using quietRun
or subprocess.Popen
to call tcpdump -i any -w capture.pcap
however these do not seem to capture the traffic for my hosts, or they stall until I ctrl+c and/or go straight to the CLI(net).
For reference; this is all using mininet CLI - the aim is to do this programmatically
Below is the current code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# from sys import exit # pylint: disable=redefined-builtin
import sys
import os
import subprocess
import time
from functools import partial
from mininet.node import Host, UserSwitch, OVSKernelSwitch, Controller, Switch
from mininet.topo import Topo, SingleSwitchTopo
from mininet.util import quietRun, pmonitor
from mininet.log import error, lg, info, setLogLevel
from mininet.net import Mininet
from mininet.cli import CLI
from mininet.link import TCLink
class ExperimentTopology(Topo):
"""Custom mininet topology for robot-controller experiments"""
def __init__(self):
"""Create custom topology"""
# Initialize topology
Topo.__init__(self)
# Add hosts and switches
switch = self.addSwitch("s1")
h1= self.addHost("h1")
h2= self.addHost("h2")
# Set link parameters (delay, etc.)
# bw = Bandwidth in Mbps
# delay = Link delay (s, ms, us)
# loss = Percentage packet loss
# max_queue_size = Maximum queue size
# use_htb = Use the Hierarchical Token Bucket rate limiter and netem delay/loss emulator?
# linkopts = dict(bw=10, delay="5ms", loss=10) #max_queue_size=1000
# Add links
self.addLink(switch, h1) # to use params, add ", **linkopts"
self.addLink(switch, h2)
def main():
lg.setLogLevel("info")
# quietRun('tcpdump -i any -w capture.pcap')
net = Mininet(topo=ExperimentTopology(), waitConnected=True)
net.start()
h1= net.get('h1')
h1p= robot.popen('python3 tls_server.py -i %s -p %d &' % (str(h1.IP()), 443))
# time.sleep(10)
h2 = net.get('h2')
h2.cmd('python3 tls_client.py -i %s -p %d -m %s -d %s -s %s' % (str(h2.IP()), 443, 'x', 1, '12.5'))
# net.popen('tcpdump -i any -w capture.pcap') # _process = subprocess.Popen(['sudo', 'tcpdump', '-i', 'any', '-w', 'capture.pcap'])
s1 = net.get('s1')
s1.cmd(os.system('sudo tshark -w $HOME/captures/capture.pcap'))
CLI(net)
h1p.terminate()
net.stop()
# _process.terminate()
if __name__ == '__main__':
main()
** EDIT: TLS client and server files:: **
tls_client.py:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import ssl
import optparse
import time
from scapy.all import *
load_layer("usb")
parser = optparse.OptionParser()
parser.add_option('-i', dest='ip', default='127.0.0.1')
parser.add_option('-p', dest='port', type='int', default=12345)
parser.add_option('-m', dest='movement', default='x')
parser.add_option('-d', dest='distance', type='int', default=1)
parser.add_option('-s', dest='speed', default='12.5')
(options, args) = parser.parse_args()
hostname = options.ip # '127.0.0.1'
port = options.port # 443
context = ssl.SSLContext()
# Confirm these min + max values
MIN_X = 150
MAX_X = 300
MIN_Y = -230
MAX_Y = 230
MIN_Z = -50
MAX_Z = 150
MIN_SPEED = 12.5 # 12.5, 25, 50, 100
MAX_SPEED = 100.0
NUM_RUNS = 5
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print(ssock.version())
# Load pcap file
# x_packets = rdpcap('pcaps/operation_move_x.pcapng')
# Now we have handshake and socket open, lets send messages
# Get data from wireshark dump, and use ssock.sendall(bytes)
# TODO: Set these (x,y,z) to the default starting values for robot
i = 0
g = 0
x = 0.00
y = 0.00
z = 0.00
f = options.speed # 12.5
if options.movement == 'x':
for j in range(NUM_RUNS):
i = 0
for k in [k for k in range(MIN_X, MAX_X+1, int(options.distance))]:
x = k
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'y':
for j in range(NUM_RUNS):
i = 0
for k in [k for k in range(MIN_X, MAX_X+1, int(options.distance))]:
y = k
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'z':
for j in range(NUM_RUNS):
i = 0
for k in [k for k in range(MIN_X, MAX_X+1, int(options.distance))]:
z = k
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'xy':
for i in range(NUM_RUNS):
i = 0
for k in [k for k in range(MIN_X, MAX_X+1, int(options.distance))]: # y pos will be x-120 (too keep in Y range)
x = k
y = k-120
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'xz':
for i in range(NUM_RUNS):
i = 0
z = 0
for k in [k for k in range(MIN_X, MAX_X+1, int(options.distance))]: # z pos will be (x/10)+5 (too keep in Z range)
x = k
if z == MAX_Z:
z = MAX_Z
else:
z += 1
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'yz':
for i in range(NUM_RUNS):
i = 0
z = 0
for k in [k for k in range(MIN_Y, MAX_Y+1, int(options.distance))]:
y = k
if z >= MAX_Z:
z = 0
else:
z += 1
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
elif options.movement == 'xyz':
for i in range(NUM_RUNS):
i = 0
y = MIN_Y
z = MIN_Z
for k in [k for k in range(MIN_X, MAX_X+1)]:
x = k
if y >= MAX_Y:
y = 0
else:
y += 1
if z >= MAX_Z:
z = 0
else:
z += 1
payload = '#' + str(i) + ' G' + str(g) + ' X' + str(x) + ' Y' + str(y) + ' Z' + str(z) + ' F' + str(f)
ssock.sendall(bytes(payload, encoding='utf-8'))
time.sleep(1)
i += 1
** tls_server.py **
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import ssl
import optparse
parser = optparse.OptionParser()
parser.add_option('-i', dest='ip', default='')
parser.add_option('-p', dest='port', type='int', default=12345)
(options, args) = parser.parse_args()
hostname = options.ip # '127.0.0.1'
port = options.port # 443
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('robot.cert', 'robot.key')
print('Loaded certificate and key..')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
print('Socket starting..')
sock.bind((hostname, port))
sock.listen(25)
with context.wrap_socket(sock, server_side=True) as ssock:
print('Socket connection established!')
(conn, addr) = ssock.accept()
f = open('server_output.txt', 'w')
while True:
message = conn.recv()
if not message:
break
# message = message.decode()
f.write('%s: %s\n' % (addr, message))
f.flush()
# print(message)
I have done this in the past by using the node's popen method to start the pcap and then the terminate to close the process and force it to record the pcap.
Say you have a node called h1. Then you can do
h1_pcap = h1.popen('tcpdump -w h1_dump.pcap')
# Do stuff here
# ...
h1_pcap.terminate()
This should record all traffic on h1 into h1_dump.pcap once the script is executed.