How to generate socket errors on network bridge - linux

I am trying to create a test environment to test the handling of network errors between a client and a server. I cannot change the software on either. The two devices will be connected across a Linux bridge and I will be using various bandwidth shaping tools to restrict bandwidth or block traffic altogether to simulate various error conditions.
Another thing I need to do, which I have no idea yet how to achieve, is to generate socket errors on existing connections. I'd prefer to use an existing Linux tool/utility, but may be able to write my own with enough guidance. I'm pretty familiar with basic networking, TCP and UDP and all that, but not with bridging.
Can anyone suggest a way I can generate socket errors, e.g. by triggering unexpected FIN packets, to both ends of a socket that connects across a bridge?
Thanks in advance.

You can generate with scapy FIN or RST packets easily sniffing in the bridge (usually br0) and crafting proper RST or FIN packets.
Here goes an example, where a RST is sent in the same direction of a packet with data.
#!/usr/bin/python
from scapy.all import *
import random
def sendRST(p):
flags = p.sprintf("%TCP.flags%")
if flags != "S":
ip = p[IP] # Received IP Packet
tcp = p[TCP] # Received TCP Segment
if ip.len <= 40:
return
i = IP() # Outgoing IP Packet
i.dst = ip.dst
i.src = ip.src
t = TCP() # Outgoing TCP Segment
t.flags = "R"
t.dport = tcp.dport
t.sport = tcp.sport
t.seq = tcp.seq
new_ack = tcp.seq + 1
print "RST sent to ",i.dst,":",t.dport
send(i/t)
while (1):
PKT = sniff (iface = "br0", filter = "tcp and src host x.x.x.x", count=1, prn=sendRST)
exit()
Check the options of sniff, wich is extremely powerfull :)
Hope to help you.

Related

How do I decode whether a network packet is SSH or not using python and the library Scapy

I am using Python 3.7 and the Scapy library and I am unable to detect if a TCP packet is SSH or not.
I have tried to find an example, but have not found one that shows how to do this.
from scapy.all import *
self.__Pkts = rdpcap("sample.pcap")
pkt = self.__Pkts[i]
if pkt.haslayer('IP'):
self.__NumIpPkts += 1
has_ssh = self.__Pkts[i]['IP'].getlayer('TCP').getlayer('SSH')
if pkt.haslayer('TCP') or has_ssh:
self.__NumTcpPkts += 1
The code presented is able to detect IP and TCP packets, but it cannot detect SSH packets. I want to detect SSH packets.
It seems like Scapy does not come with a SSH layer implementation out of the box. What you can easily do is check whether the TCP packet is using port 22 and then in those cases assume it is an SSH packet and store the raw layer data.
If you want to do a more elaborate check you will have to implement your own scapy layer or find one on the internet: https://github.com/tintinweb/scapy-ssh/blob/master/src/scapy/layers/ssh.py
I have not tested the implementation provided in the link and I would suggest using it merely as a template for your own implementation while also following https://scapy.readthedocs.io/en/latest/build_dissect.html

UDP socket file transfer python 3.5

How do i transfer a large file (video,audio) from my client to server in the local host using UDP sockets in python 3.5? I was able to send a small .txt file but not other file types. Please give me suggestions.
Thank you!
Here is my code to transfer a text file.
CLIENT CODE:
import socket
import sys
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host = '127.0.0.1'
port=6000
msg="Trial msg"
msg=msg.encode('utf-8')
while 1:
s.sendto(msg,(host,port))
data, servaddr = s.recvfrom(1024)
data=data.decode('utf-8')
print("Server reply:", data)
break
s.settimeout(5)
filehandle=open("testing.txt","rb")
finalmsg=filehandle.read(1024)
s.sendto(finalmsg, (host,port))
SERVER CODE:
import socket
host='127.0.0.1'
port=6000
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind(("",port))
print("waiting on port:", port)
while 1:
data, clientaddr= s.recvfrom(1024)
data=data.decode('utf-8')
print(data)
s.settimeout(4)
break
reply="Got it thanks!"
reply=reply.encode('utf-8')
s.sendto(reply,clientaddr)
clientmsg, clientaddr=s.recvfrom(1024)
Don't use UDP for transferring large files, use TCP.
UDP does not garauntee all packets you send will arrive, or if they will arrive in order, they may even be duplicated. Furthermore UDP is not suited to large transfers because 1) it has no congestion control so you will just flood the network and the packets will be dropped, and, 2) you would have to break up your packets into smaller ones usually about 1400 bytes is recommended to keep under MTU otherwise if you rely on IP fragmentation and one fragment is lost your whole file is lost .. You would have to write custom code to fix all these issues with UDP since file transfers require everything to be sent reliably.
TCP on the other hand already does all this, it is reliable, has congestion control and is ubiquitous - you are viewing this web page over HTTP which is on top of TCP.
If you must use UDP instead of TCP or an application level protocol then, you should be able to 'generate redundant blocks' with a package like zfec so that you can reconstruct the original data even if not all of the packets are received.

Send TCP SYN packet with payload

Is it possible to send a SYN packet with self-defined payload when initiating TCP connections? My gut feeling is that it is doable theoretically. I'm looking for a easy way to achieve this goal in Linux (with C or perhaps Go language) but because it is not a standard behavior, I didn't find helpful information yet. (This post is quite similar while it is not very helpful.)
Please help me, thanks!
EDIT: Sorry for the ambiguity. Not only the possibility for such task, I'm also looking for a way, or even sample codes to achieve it.
As far as I understand (and as written in a comment by Jeff Bencteux in another answer), TCP Fast Open addresses this for TCP.
See this LWN article:
Eliminating a round trip
Theoretically, the initial SYN segment could contain data sent by the initiator of the connection: RFC 793, the specification for TCP, does permit data to be included in a SYN segment. However, TCP is prohibited from delivering that data to the application until the three-way handshake completes.
...
The aim of TFO is to eliminate one round trip time from a TCP conversation by allowing data to be included as part of the SYN segment that initiates the connection.
Obviously if you write your own software on both sides, it is possible to make it work however you want. But if you are relying on standard software on either end (such as, for example, a standard linux or Windows kernel), then no, it isn't possible, because according to TCP, you cannot send data until the session is established, and the session isn't established until you get an acknowledgment to your SYN from the other peer.
So, for example, if you send a SYN packet that also includes additional payload to a linux kernel (caveat: this is speculation to some extent since I haven't actually tried it), it will simply ignore the payload and proceed to acknowledge (SYN/ACK) or reject (with RST) the SYN depending on whether there's a listener.
In any case, you could try this, but since you're going "off the reservation" so to speak, you would need to craft your own raw packets; you won't be able to convince your local OS to create them for you.
The python scapy package could construct it:
#!/usr/bin/env python2
from scapy.all import *
sport = 3377
dport = 2222
src = "192.168.40.2"
dst = "192.168.40.135"
ether = Ether(type=0x800, dst="00:0c:29:60:57:04", src="00:0c:29:78:b0:ff")
ip = IP(src=src, dst=dst)
SYN = TCP(sport=sport, dport=dport, flags='S', seq=1000)
xsyn = ether / ip / SYN / "Some Data"
packet = xsyn.build()
print(repr(packet))
TCP Fast open do that. But both ends should speak TCP fast open. QUIC a new protocol is based to solve this problem AKA 0-RTT.
I had previously stated it was not possible. In the general sense, I stand by that assessment.
However, for the client, it is actually just not possible using the connect() API. There is an alternative connect API when using TCP Fast Open. Example:
sfd = socket(AF_INET, SOCK_STREAM, 0);
sendto(sfd, data, data_len, MSG_FASTOPEN,
(struct sockaddr *) &server_addr, addr_len);
// Replaces connect() + send()/write()
// read and write further data on connected socket sfd
close(sfd);
There is no API to allow the server to attach data to the SYN-ACK sent to the client.
Even so, enabling TCP Fast Open on both the client and server may allow you to achieve your desired result, if you only mean data from the client, but it has its own issues.
If you want the same reliability and data stream semantics of TCP, you will need a new reliable protocol that has the initial data segment in addition to the rest of what TCP provides, such as congestion control and window scaling.
Luckily, you don't have to implement it from scratch. The UDP protocol is a good starting point, and can serve as your L3 for your new L4.
Other projects have done similar things, so it may be possible to use those instead of implementing your own. Consider QUIC or UDT. These protocols were implemented over the existing UDP protocol, and thus avoid the issues faced with deploying TCP Fast Open.

Sending raw data in Scapy does not work correctly

I use Scapy to create an initial OpenVPN packet and send it to OpenVPN server (acting as a client). OpenVPN part of the packet I'm just reusing from old captured connection, but its irrelevant here.
Thing is, I add a payload of 42bytes but for some reason when I capture packet with Wireshark, I can see 84bytes of OpenVPN stuff. Last half of that is correct payload I sent, but I can't figure out what is the first half. All other layers (Ethernet, IP, UDP) have correct size.
#!/usr/bin/env python
import socket
from scapy.all import *
mysocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
mysocket.connect(('192.168.138.129', 1194))
mystream=StreamSocket(mysocket)
ascapypacket=Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)/Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")
etherLoad = len(ascapypacket.getlayer(Ether)) # display size
print etherLoad
ipLoad = len(ascapypacket.getlayer(IP)) # display size
print ipLoad
udpLoad = len(ascapypacket.getlayer(UDP)) # display size
print udpLoad
rawLoad = len(ascapypacket.getlayer(Raw)) # display size
print rawLoad
mystream.send(ascapypacket)
I made an image. Here you can see green stuff is correct - first part is IP and UDP layers, and 2nd green part is my OpenVPN payload, but I don't understand what is the red part.
Edit: If I don't send that Raw payload I still get those 42 bytes for some reason.
You've created an ordinary UDP datagram socket:
mysocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
This socket manages the ethernet, IP & UDP layers by itself, with guidance from the user through various auxiliary methods and arguments, such as the connect method you've in fact used in your code snippet:
mysocket.connect(('192.168.138.129', 1194))
Its various send methods, even when encapsulated as part of a scapy's StreamSocket object, are expecting to receive as their "data-to-send" argument just the application payload layered above the UDP layer.
However, you're passing on to it the entire protocol stack payload, i.e. the ethernet, IP & UDP headers, which is misinterpreted to be part of the payload data that you wish to send to the other side:
ascapypacket=Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)/Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")
Thus, the data you've marked in red is actually the payload data you've yourself set, before it is followed by the OpenVPN part:
Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)
The first part marked in green, which you've mistakenly identified as created by yourself, is actually generated by the socket object (the kernel, the appropriate driver and the underlying hardware, to be more accurate).
Depending on your needs, you should either instantiate your socket as a raw one:
mysocket = socket(socket.AF_PACKET, socket.SOCK_RAW)
or set the payload accordingly as just the OpenVPN data:
ascapypacket=Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")

How to set linux kernel not to send RST_ACK, so that I can give SYN_ACK within raw socket

I want to ask a classic question about raw socket programming and linux kernel TCP handling. I've done the research to some same threads like linux raw socket programming question, How to reproduce TCP protocol 3-way handshake with raw sockets correctly?, and TCP ACK spoofing, but still can't get the solution.
I try to make a server which don't listen to any port, but sniff SYN packets from remote hosts. After the server do some calculation, it will send back a SYN_ACK packet to corresponding SYN packet, so that I can create TCP Connection manually, without including kernel's operation. I've create raw socket and send the SYN_ACK over it, but the packet cannot get through to the remote host. When I tcpdump on the server (Ubuntu Server 10.04) and wireshark on client (windows 7), the server returns RST_ACK instead of my SYN_ACK packet. After doing some research, I got information that we cannot preempt kernel's TCP handling.
Is there still any other ways to hack or set the kernel not to responds RST_ACK to those packets?
I've added a firewall to local ip of server to tell the kernel that maybe there's something behind the firewall which is waiting for the packet, but still no luck
Did you try to drop RST using iptables?
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
should do the job for you.
I recommend using ip tables, but since you ask about hacking the kernel as well, here is an explanation of how you could do that (I'm using kernel 4.1.20 as reference):
When a packet is received (a sk_buff), the IP protocol handler will send it to the networking protocol registered:
static int ip_local_deliver_finish(struct sock *sk, struct sk_buff *skb)
{
...
ipprot = rcu_dereference(inet_protos[protocol]);
if (ipprot) {
...
ret = ipprot->handler(skb);
Assuming the protocol is TCP, the handler is tcp_v4_rcv:
static const struct net_protocol tcp_protocol = {
.early_demux = tcp_v4_early_demux,
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.no_policy = 1,
.netns_ok = 1,
.icmp_strict_tag_validation = 1,
};
So tcp_v4_cv is called. It will try to find the socket for the skb received, and if it doesn't, it will send reset:
int tcp_v4_rcv(struct sk_buff *skb)
{
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
if (!sk)
goto no_tcp_socket;
no_tcp_socket:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard_it;
tcp_v4_send_reset(NULL, skb);
...
There are many different ways you can hack this. You could go to the xfrm4_policy_check function and hack/change the policy for AF_INET. Or you can just simply comment out the line that calls xfrm4_policy_check, so that the code will always go to discard_it, or you can just comment out the line that calls tcp_v4_send_reset (which will have more consequences, though).
Hope this helps.

Resources