first of all I would like to know what this python sentence does:
struct.unpack("!%sH" % (len(data) / 2), data))
And secondly, I have to make an ICMP request message using python, and the thing is that I already got some code the teacher gave me to help:
def step4(code, server, port):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
CHARMAP = nonprintable_to_dots()
packet = create_packet(int(code))
s.sendto(packet, (server, port))
while True:
msg = s.recv(1600)
if not msg:
break
ihl = (ord(msg[0]) & 0x0F) * 4
icmp = msg[ihl:]
hexdump(icmp, True)
if cksum(icmp[:]) != 0:
print("wrong ckecksum!!")
def nonprintable_to_dots():
return str.join('', [c if c in printable[:-5] else '.' for c in map(chr, range(256))])
def hexdump(frame, with_time=False):
def to_chr(bytes):
retval = bytes.translate(CHARMAP)
return retval[:8] + ' ' + retval[8:]
def to_hex(bytes):
retval = str.join(' ', ["%02X" % ord(x) for x in bytes])
return retval[:23] + ' ' + retval[23:]
if with_time:
print('--' + time.strftime("%H:%M:%s"))
for i in range(0, len(frame), 16):
line = frame[i:i + 16]
print('%04X %-49s |%-17s|' % (i, to_hex(line), to_chr(line)))
def cksum(data):
def sum16(data):
"sum all the the 16-bit words in data"
if len(data) % 2:
data += '\0'
return sum(struct.unpack("!%sH" % (len(data) / 2), data))
retval = sum16(data) # sum
retval = sum16(struct.pack('!L', retval)) # one's complement sum
retval = (retval & 0xFFFF) ^ 0xFFFF # one's complement
return retval
The thing is that theoretically all this code is right, so I only should do the "create_packet" function, which I include here:
def create_packet(code):
ICMP_REQUEST = 8
checksum = 0
identifier = 7
sequence_number = 7
message_header = struct.pack("!BBHHH", ICMP_REQUEST, 0, checksum, identifier, sequence_number)
message_payload = struct.pack("!I", code)
checksum = cksum(message_header + message_payload)
message_header = struct.pack("!BBHHH", ICMP_REQUEST, 0, checksum, identifier, sequence_number)
return message_header + message_payload
Whenever I execute the script, I always get this error:
Traceback (most recent call last):
File "gymkhana.py", line 256, in
main()
File "gymkhana.py", line 19, in main
step4(identifier, server, ginkana_port)
File "gymkhana.py", line 181, in step4
packet = create_packet(int(code))
File "gymkhana.py", line 211, in create_packet
checksum = cksum(message_header + message_payload)
File "gymkhana.py", line 248, in cksum
retval = sum16(data) # sum
File "gymkhana.py", line 246, in sum16
return sum(struct.unpack("!%sH" % (len(data) / 2), data))
struct.error: bad char in struct format
解决方案
As answer to your first question, this line
struct.unpack("!%sH" % (len(data) / 2), data) # in Python 2
struct.unpack("!%sH" % (len(data) // 2), data) # in Python 3
says, take the n bytes in data (example: 4 bytes) and interpret them as n/2 unsigned short integers (example: 2 integers) of 2 bytes each. The ! at the beginning is about byte order and means big-endian. %s gets translated to one or more digits depending on the value of len(data) / 2, so in the example, it is the same as doing
struct.unpack("!2H", data)
Your bad char in struct format exception is because the code you present uses the / division operator. That is valid in Python 2. But in Python 3 it needs to be //. That is because / means integer division in Python 2, but floating-point division in Python 3. So in Python 3,
"!%sH" % (len(data) / 2)
comes out as
struct.unpack("!2.0H", data)
which explains your bad char error.