Trying to dynamically unpack data - python - python

i am trying to unpack data i receive from a packet dynamically, the main reason for this is i do not know the length of the ip addresses or the number of ip addresses in a packet, so need to unpack all
if our_or_addr_len == 4:
our_op_ip = struct.unpack(">BBBB", payload[6:10])
num_their_ips = struct.unpack(">B", payload[10])[0]
len_their_ips = struct.unpack(">B", payload[12])[0]
# Much better way to unpack the packet, does unpacking dynamically rather than set values
byte_string = '>{}'.format('b'*len_their_ips)
their_ips = []
for count in range(num_their_ips):
start = 13 + (count*len_their_ips)
end = start + len_their_ips
ip = struct.unpack(byte_string, payload[start:end])
print 'IP #{}: {}'.format(count+1, ip)
their_ips.append(ip)
return { 'tm': tm, 'our_or_ip_version': our_or_ip_version, 'our_or_addr_len': our_or_addr_len, 'our_op_ip': our_op_ip, 'num_their_ips': num_their_ips, 'len_their_ips': len_their_ips, 'their_ips': their_ips }
above is currently my code
what it should do is if my ip address is that of an ip v4 for, the for all of their ip address to unpack them for the packet starting at 13 in the payload for the length of their ip address for the number of ip addresses contained
currently it is only outputting one ip address although there is 2 ip address in the payload
shown in this output
{'our_or_addr_len': 4, 'len_their_ips': 4, 'our_op_ip': (00, 00, 00, 00), 'their_ips': [(0, 00, 00, 0)], 'tm': 1402265584, 'our_or_ip_version': 4, 'num_their_ips': 2}
how can i get both of the ip addresses returned, is there an issue with the loop as i think it should work so am confused as to why only one ip is returned

Managed to fix it it seemed my indenting was out on the their_ips.append(ip) so it was not getting assigned properly, weird how i had no errors however on complie, anyone got a good IDE program for linux and python ?

Related

Generating a UDP message in python with a header and payload in python3

I am new to Networking and trying to implement a network calculator using python3 where the client's responsibility is to send operands and operators and the server will calculate the result and send it back to the client. Communication is through UDP messages and I am working on client side. Each message is comprised of a header and a payload and they are described as shown in the below figures.
UDP header:
I am familiar with sending string messages using sockets but having a hard-time with how to make a message with both header and payload and how to assign the bits for various attributes or how to generate message/client id's in the header and If there is any way to automatically generate the Id's. Any help or suggestions will be highly appreciated.
Thanks in advance
I will only do a portion of your homework.
I hope it will help you to find energy to work on missing parts.
import struct
import socket
CPROTO_ECODE_REQUEST, CPROTO_ECODE_SUCCESS, CPROTO_ECODE_FAIL = (0,1,2)
ver = 1 # version of protocol
mid = 0 # initial value
cid = 99 # client Id (arbitrary)
sock = socket.socket( ...) # to be customized
def sendRecv( num1, op, num2):
global mid
ocs = ("+", "-", "*", "/").index( op)
byte0 = ver + (ocs << 3) + (CPROTO_ECODE_REQUEST << 6)
hdr = struct.pack( "!BBH", byte0, mid, cid)
parts1 = (b'0000' + num1.encode() + b'0000').split(b'.')
parts2 = (b'0000' + num2.encode() + b'0000').split(b'.')
msg = hdr + parts1[0][-4:] + parts1[1][:4] + parts2[0][-4:] + parts2[1][:4]
socket.send( msg) # send request
bufr = socket.recv( 512) # get answer
# to do:
# complete socket_send and socket.recv
# unpack bufr into: verr,ecr,opr,value_i, value_f
# verify that verr, ecr, opr, are appropriate
# combine value_i and value_f into answer
mid += 1
return answer
result = sendRecv( '2.47', '+', '46.234')
There are many elements that haven't be specified by your teacher:
what should be the byte-ordering on the network (bigEndian or littleEndian)? The above example suppose it's bigEndian but you can easily modify the 'pack' statement to use littleEndian.
What should the program do if the received packet header is invalid?
What should the program do if there's no answer from server?
Payload: how should we interpret "4 most significant digits of fraction"? Does that mean that the value is in ASCII? That's not specified.
Payload: assuming the fraction is in ASCII, should it be right-justified or left-justified in the packet?
Payload: same question for integer portion.
Payload: if the values are in binary, are they signed or unsigned. It will have an affect on the unpacking statement.
In the program above, I assumed that:
values are positive and in ASCII (without sign)
integer portion is right-justified
fractional portion is left justified
Have fun!

Using Scapy to send Fragment Packets with random Offsets

I would like to send fragmented packets size of 8 bytes and a random starting offset. Also want to leave out the last fragmented packet.
So far I got everything except the fragment of
from scapy.all import *
from random import randint
dip="MY.IP.ADD.RESS"
payload="A"*250+"B"*500
packet=IP(dst=dip,id=12345,off=123)/UDP(sport=1500,dport=1501)/payload
frags=fragment(packet,fragsize=8)
print(packet.show())
for f in frags:
send(f)
What does the above code do?
It sends IP Fragment Packets size of 8 byte to a destination IP address.
I would like to send IP Fragment Packets with a random Frag Offset.
I can't find anything about fragment() and the only field, I was able to edit was in IP packet instead of each fragmented IP packet.
Does someone have an idea to accomplish this?
Infos: Python2.7, latest version of scapy (pip)
If you want to generate "broken" fragment offset fields, you have to do that yourself. The scapy fragment() function is simple enough:
def fragment(pkt, fragsize=1480):
"""Fragment a big IP datagram"""
fragsize = (fragsize + 7) // 8 * 8
lst = []
for p in pkt:
s = raw(p[IP].payload)
nb = (len(s) + fragsize - 1) // fragsize
for i in range(nb):
q = p.copy()
del(q[IP].payload)
del(q[IP].chksum)
del(q[IP].len)
if i != nb - 1:
q[IP].flags |= 1
q[IP].frag += i * fragsize // 8 # <---- CHANGE THIS
r = conf.raw_layer(load=s[i * fragsize:(i + 1) * fragsize])
r.overload_fields = p[IP].payload.overload_fields.copy()
q.add_payload(r)
lst.append(q)
return lst
Source: https://github.com/secdev/scapy/blob/652b77bf12499451b47609b89abc663aa0f69c55/scapy/layers/inet.py#L891
If you change the marked code line above, you can set the fragment offset to whatever you want.

add option in tcp with scapy

Upon the receive of a TCP ACK (with option experiment) like this
I want to generate a TCP SYN+ACK (with option experiment and Fast Open Cookie) as indicated below
I want to generate the TCP SYN+ACK with scapy so I added
So I added 254 : ("RFC3692-style Experiment","!HHH") in the /usr/share/pyshared/scapy/layers/inet.py like this
TCPOptions = (
{ 0 : ("EOL",None),
1 : ("NOP",None),
2 : ("MSS","!H"),
3 : ("WScale","!B"),
4 : ("SAckOK",None),
5 : ("SAck","!"),
8 : ("Timestamp","!II"),
14 : ("AltChkSum","!BH"),
15 : ("AltChkSumOpt",None),
25 : ("Mood","!p"),
254 : ("Experiment","!HHHH")
},
{ "EOL":0,
"NOP":1,
"MSS":2,
"WScale":3,
"SAckOK":4,
"SAck":5,
"Timestamp":8,
"AltChkSum":14,
"AltChkSumOpt":15,
"Mood":25,
"Experiment":254
} )
And upon the receive of the TCP ACK (with experiment option), I executhe the following scapy function:
TCP_SYNACK=TCP(sport=Ddport, dport=Ssport, flags="SA", seq=SeqNr, ack=AckNr, options=[('Experiment',0xf989,0xcafe,0x0102,0x0002),('NOP',0),('NOP',0)])
ANSWER=sr1(ip/TCP_SYNACK)
But I got a python error. It looks like I made error in the definition of the option field in the TCP packet with scapy. What I m doing wron?
I think you need to specify the optional field's value in a tuple format, as follows:
TCP_SYNACK = TCP(sport=Ddport, dport=Ssport, flags="SA", seq=SeqNr, ack=AckNr, options=[('Experiment', (0xf989, 0xcafe, 0x0102, 0x0002)), ('NOP', 0), ('NOP', 0)])
but I had the same problem. You can actually put an integer as the first element of your options tuple. I wanted to put in a hash, so I used the following code in scapy:
pkt = TCP(options=[("NOP", None), (19, "\xff\xff\xff\xff\xff\xff")])

How to send an array by i2c?

I've been trying for several days now to send a python array by i2c.
data = [x,x,x,x] # `x` is a number from 0 to 127.
bus.write_i2c_block_data(i2c_address, 0, data)
bus.write_i2c_block_data(addr, cmd, array)
In the function above: addr - arduino i2c adress; cmd - Not sure what this is; array - python array of int numbers. Can this be done? What is actually the cmd?
FWIW, Arduino code, where I receive the array and put it on the byteArray:
void receiveData(int numByte){
int i = 0;
while(wire.available()){
if(i < 4){
byteArray[i] = wire.read();
i++;
}
}
}
It gives me this error: bus.write_i2c_block_data(i2c_adress, 0, decodedArray) IOError: [Errno 5] Input/output error. I tried with this: bus.write_byte(i2c_address, value), and it worked, but only for a value that goes from 0 to 127, but, I need to pass not only a value, but a full array.
The function is the good one.
But you should take care of some points:
bus.write_i2c_block_data(addr, cmd, []) send the value of cmd AND the values in the list on the I2C bus.
So
bus.write_i2c_block_data(0x20, 42, [12, 23, 34, 45])
doesn't send 4 bytes but 5 bytes to the device.
I doesn't know how the wire library work on arduino, but the device only read 4 bytes, it doesn't send the ACK for the last bytes and the sender detect an output error.
Two convention exist for I2C device address. The I2C bus have 7 bits for device address and a bit to indicate a read or a write. An other (wrong) convention is to write the address in 8 bits, and say that you have an address for read, and an other for write. The smbus package use the correct convention (7 bits).
Exemple: 0x23 in 7 bits convention, become 0x46 for writing, and 0x47 for reading.
It took me a while,but i got it working.
On the arduino side:
int count = 0;
...
...
void receiveData(int numByte){
while(Wire.available()){
if(count < 4){
byteArray[count] = Wire.read();
count++;
}
else{
count = 0;
byteArray[count] = Wire.read();
}
}
}
On the raspberry side:
def writeData(arrayValue):
for i in arrayValue:
bus.write_byte(i2c_address, i)
And that's it.
cmd is offset on which you want to write a data.
so its like
bus.write_byte(i2c_address, offset, byte)
but if you want to write array of bytes then you need to write block data so your code will look like this
bus.write_i2c_block_data(i2c_address, offset, [array_of_bytes])

How can i find the ips in network in python

How can i find the TCP ips in network with the range(i.e 132.32.0.3 to 132.32.0.44) through python programming and also want to know the which ips are alive and which are dead. please send me.. thanks for the repliers...
Part 1 - "Finding IPs"
Your example range, 132.32.0.3 to 132.32.0.44 doesn't match any subnet, which is curious.
Typically applications for checking whether hosts are up and down are normally scoped within a subnet, e.g. 192.168.0.0/28 (host addresses: 192.168.0.1 to 192.168.0.14).
If you wanted to calculate the addresses within a subnet, I'd suggest you use ipaddr. E.g.:
>>> from ipaddr import IPv4Address, IPNetwork
>>> for a in IPNetwork('192.168.0.0/28').iterhosts():
... print a
...
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
192.168.0.11
192.168.0.12
192.168.0.13
192.168.0.14
However, if you're sure that you want an arbitrary range. You can convert an IPv4 address to an integer, increment and convert back to dotted IP. E.g.:
def aton(a):
"""
Change dotted ip address to integer
e.g. '192.168.0.1' -> 3232235521L
"""
return reduce(lambda x,y: (x<<8) + y, [ int(x) for x in a.split('.') ])
def ntoa(n):
"""
Change an integer to a dotted ip address.
e.g. 3232235522L -> '192.168.0.2'
"""
return "%d.%d.%d.%d" % (n >> 24,(n & 0xffffff) >> 16,(n & 0xffff) >> 8,(n & 0xff))
def arbitraryRange(a1,a2):
"""
Generate all IP addresses between two addresses inclusively
"""
n1, n2 = aton(a1), aton(a2)
assert n1 < n2
i = n1
while i <= n2:
yield ntoa(i)
i += 1
Providing:
>>> for a in arbitraryRange('192.168.0.10','192.168.0.20'):
... print a
...
192.168.0.10
192.168.0.11
192.168.0.12
192.168.0.13
192.168.0.14
192.168.0.15
192.168.0.16
192.168.0.17
192.168.0.18
192.168.0.19
192.168.0.20
Part 2 - "Alive or Dead"
The question of "alive" or "dead" is complex and entirely dependent on what you mean by those terms. To provide context and contrast, here's a list of testable qualities with regard to an IP address / host:
Responds to ARP request?
Responds to ICMP echo request?
Responds to TCP SYN?

Categories

Resources