• Python socket编程之构造IP首部和ICMP首部


    这两天在做一个实验需要自己构造IP首部,遇到诸多问题,搞了一天终于搞定。

    关于socket的介绍网上一大堆,我只记录构造IP头时我遇到的问题。由于没玩过socket构造IP首部,网上找了段代码研究下,无奈代码跑不动,各种问题,网上搜集资料无果,从基础学起,加上自己的脑洞总算解决了。

    我想自己构造一个自定义IP头的ICMP回送请求,网上找了段代码,自己改了改,现在长这个样子:

     1 import socket
     2 import struct
     3 def checksum(source_string):
     4     sum = 0
     5     countTo = (len(source_string)/2)*2
     6     count = 0
     7     while count<countTo:
     8         thisVal = ord(source_string[count + 1])*256 + ord(source_string[count])
     9         sum = sum + thisVal
    10         sum = sum & 0xffffffff 
    11         count = count + 2
    12     if countTo<len(source_string):
    13         sum = sum + ord(source_string[len(source_string) - 1])
    14         sum = sum & 0xffffffff 
    15     sum = (sum >> 16)  +  (sum & 0xffff)
    16     sum = sum + (sum >> 16)
    17     answer = ~sum
    18     answer = answer & 0xffff
    19     answer = answer >> 8 | (answer << 8 & 0xff00)
    20     return answer
    21 def ping(ip):
    22     s=socket.socket(socket.AF_INET,socket.SOCK_RAW,255)
    24     s.setsockopt(0, socket.IP_HDRINCL, 1)
    25 # now start constructing the packet
    26  
    27     source_ip = '172.16.12.1'
    28     dest_ip = ip
    29  
    30 # ip header fields
    31     ihl = 5
    32     version = 4
    33     tos = 0
    34     tot_len = 28
    35     id = 0
    36     frag_off = 0
    37     ttl = 255
    38     protocol = 1
    39     check = 0  
    40     saddr =socket.inet_aton ( source_ip )  #Spoof the source ip address if you want to
    41     daddr = socket.inet_aton ( dest_ip )
    44     ihl_version = (version << 4) + ihl
    45     # the ! in the pack format string means network order
    46     ip_header = struct.pack('!BBHHHBBH4s4s', ihl_version, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr)
    47     packet = struct.pack(
    48             "!BBHHH", 8, 0, 0, 0, 0
    49     )
    50     chksum=checksum(packet)
    51     packet = struct.pack(
    52             "!BBHHH", 8, 0, chksum, 0, 0
    53     )
    54     packet=ip_header+packet
    55     s.sendto(packet,(ip,1))
    56     print "done"
    57     
    58 if __name__=='__main__':
    59     ping('172.31.0.1')

    步骤很简单,就是自己创建个套接字,然后把头构造好再发送就行了,但是一般的套接字是无法自己更改IP头的,只能从IP数据报的数据部分开始构造,想要构造IP首部就要用到原始套接字,用原始套接字可以从IP首部开始构造,但是如果用原始套接字需要root权限,开始我在OS X下用IDE,程序总是报错socket.error: [Errno 1] Operation not permitted,就是因为权限的问题,在终端里sudo运行就没有权限问题了(Ps:如果想用root权限打开IDE,又不想切换账户的话,终端里sudo ./IDE就行了)现在有了权限,开始报别的错了,提示socket.error: [Errno 22]Invalid argument。

    这是创建原始套接字的代码,第一行第三个值255是IPPROTO_RAW的值,如果要构造IP头,就要加上第二行代码设置IP_HDRINCL,第一个值0是IPPROTO_IP的值

    s=socket.socket(socket.AF_INET,socket.SOCK_RAW,255)
    s.setsockopt(0, socket.IP_HDRINCL, 1)

    如果这样设置在OS X下就会在调用sendto()的位置报Invalid argument错误,后来发现问题出在第一行的第三个参数255上,经测试发现

    在OS X下,这个参数置成0或255都会报错

    在WINDOWS下 ,这个参数置成0或255都不会报错

    在LINUX下,这个参数置成0会报错,置成255不会报错

    现在可以构造任意的源IP和目的IP的ICMP回送请求了,IP首部字段的ID,长度,校验和置成0就可以,内核协议栈会修正。

    在linux上抓包发现目的IP为同子网下不存在的主机IP时,是抓不到ICMP包的,这是因为主机先发送ARP包请求目的IP的MAC地址得不到回应,而不能进一步发送ICMP回送请求,也就是说PING命令中提示的Request timeout for icmp_seq是因为ARP请求得不到应答而产生的。

  • 相关阅读:
    PHP 上传与下载
    PHP OOP 魔术方法
    PHP的错误处理
    初识PHP
    MUI实现上拉刷新和下拉加载
    解决 windows npm ERR! asyncWrite is not a function 问题
    浅谈angular2与angularJS的区别
    AngularJS内建服务以及自定义服务的用法
    mysql与mysqli的一些区别和方法
    数据库基础和三大范式以及基本的增删改查命令
  • 原文地址:https://www.cnblogs.com/duanv/p/4592191.html
Copyright © 2020-2023  润新知