• raw socket 发送数据包


    TRawSocket = class(TObject)
    private
        buf: array[0..BUFLEN - 1] of char;
        FdwNotifyWnd: Cardinal;
        hsocket: Cardinal;
        str: string;
    public
        constructor Create;
        destructor Destroy; override;
        function createSocket: Integer;
        procedure destroySocket;
        function IsOk: Boolean;
        //function sendTcpData(srcIP, dstIP: string; srcPort, dstPort: word; data:
          //pchar; dataLen: integer): Integer;
        function sendUdpData(srcIP, dstIP: string; srcPort, dstPort: word; data:
          pchar; dataLen: integer): Integer;
        function sendUdpDataFrag(srcIP, dstIP: string; srcPort, dstPort: word;
          data: pchar; dataLen: integer): Integer;
    published
        property dwNotifyWnd: Cardinal read FdwNotifyWnd write FdwNotifyWnd;
    end;
    constructor TRawSocket.Create;
    begin
    inherited Create;
    hsocket := INVALID_SOCKET;
    end;destructor TRawSocket.Destroy;
    begin
    if IsOk then destroySocket;
    inherited Destroy;
    end;function TRawSocket.createSocket: Integer;
    var
    flag: Integer;
    ret: Integer;
    begin
    // 创建raw socket,自己构造ip包头
    result := -1; // Create socket
    // IPPROTO_RAW 只能用来发送IP包,而不能接收任何数据.
    //*发送的数据需要自己填充IP包头,TCP/UDP头并且自己计算校验和
    hsocket := Socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (hsocket = INVALID_SOCKET) then begin
        str := 'Socket() failed: ' + IntToStr(WSAGetLastError);
        SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
        exit;
    end;flag := 1; // Option: Header Include
    ret := SetSockOpt(hsocket, IPPROTO_IP, IP_HDRINCL, @flag, SizeOf(flag));
    if ret = SOCKET_ERROR then begin
        str := 'setsockopt IP_HDRINCL failed: ' + IntToStr(WSAGetLastError);
        SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
        exit;
    end;flag := 5000; // Option: Send OverTime;
    ret := SetSockOpt(hsocket, SOL_SOCKET, SO_SNDTIMEO, @flag, SizeOf(flag));
    if ret = SOCKET_ERROR then begin
        str := 'setsockopt SO_SNDTIMEO failed: ' + IntToStr(WSAGetLastError);
        SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
        exit;
    end;
    result := 1;
    end;procedure TRawSocket.destroySocket;
    begin
    shutdown(hsocket, SD_BOTH);
    CloseSocket(hsocket);
    hsocket := INVALID_SOCKET;
    end;function TRawSocket.IsOk: Boolean;
    begin
    result := not (hsocket = INVALID_SOCKET);
    end;
    function TRawSocket.sendUdpData(srcIP, dstIP: string; srcPort, dstPort: word;
    data: pchar; dataLen: integer): Integer;
    var
    ipHdr: _ipHead;
    udpHdr: _udpHead;
    pseudoHdr: _pseudoHead;
    ipSize, udpSize: Word;
    iphdrlen, pseudohdrlen, udphdrlen: Word;
    lpipHdr: pipHead;
    lpudpHdr: pudpHead;
    p, p0: PChar;
    Local: TSockAddrIn;
    Remote: TSockAddrIn;
    begin
    // 功能:打包发送UDP包
    Local.sin_family := AF_INET;
    Local.sin_addr.S_addr := inet_Addr(PChar(srcIP));
    Local.sin_port := htons(srcPort);Remote.sin_family := AF_INET;
    Remote.sin_addr.S_addr := inet_Addr(PChar(dstIP));
    Remote.sin_port := htons(dstPort);iphdrlen := sizeof(_ipHead);
    udphdrlen := sizeof(_udpHead);
    pseudohdrlen := sizeof(pseudoHdr);
    ipSize := iphdrlen + udphdrlen + datalen;
    udpSize := ipSize - iphdrlen;
    inc(idt); // test
    // 初始化 IP 头
    ipHdr.ver_IHL := (4 shl 4) or (sizeof(ipHdr) div 4);
    ipHdr.serverType := 0; // IP type of service
    ipHdr.totalLen := htons(ipSize); // Total packet len
    ipHdr.ident := htons(idt); // Unique identifier: set to 0
    ipHdr.flags_off := 0; // Fragment offset field
    ipHdr.ttl := 128; // Time to live
    ipHdr.protocol := 17; // Protocol(UDP)
    ipHdr.ipchksum := 0; // IP checksum
    ipHdr.srcAddr := Local.sin_addr.S_addr; // Source address
    ipHdr.dstAddr := Remote.sin_addr.S_addr; // Destination address// 初始化 UDP 头
    udpHdr.srcPort := Local.sin_port;
    udpHdr.dstPort := Remote.sin_port;
    udpHdr.Length := htons(udpSize);
    udpHdr.checksum := 0;// 初始化 伪ip 头
    pseudoHdr.srcAddr := ipHdr.srcAddr;
    pseudoHdr.dstAddr := ipHdr.dstAddr;
    pseudoHdr.unused := 0;
    pseudoHdr.protocol := ipHdr.protocol;
    pseudoHdr.Length := udpHdr.Length;p := buf + iphdrlen - pseudohdrlen;
    p0 := P; // 备份伪ip头指针p0,checksum 运算用
    move(pseudoHdr, p^, pseudohdrlen);
    inc(p, pseudohdrlen);
    lpudpHdr := pudpHead(p);
    move(udpHdr, p^, udphdrlen);
    inc(p, udphdrlen);
    move(data^, p^, datalen);
    inc(p, datalen);
    lpudpHdr^.checksum := checksum(p0, p - p0);
    // copy ip头;覆盖伪ip头
    p := buf;
    lpipHdr := pipHead(p);
    move(ipHdr, p^, iphdrlen);
    lpipHdr^.ipchksum := checksum(buf, iphdrlen); // ip头// Send the raw socket packet
    result := sendto(hsocket, buf, ipSize, 0, @Remote, SizeOf(Remote));
    if result = SOCKET_ERROR then
    begin
        str := 'sendto() failed: ' + IntToStr(WSAGetLastError);
        SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
        exit;
    end;
    end;
    function TRawSocket.sendUdpDataFrag(srcIP, dstIP: string; srcPort, dstPort:
    word; data: pchar; dataLen: integer): Integer;
    const
    fraglen = 1472; // 分片的数据长度 1500(以太网MTU)-20(IP头长)-8(UDP头长)
    var
    ipHdr: _ipHead;
    udpHdr: _udpHead;
    pseudoHdr: _pseudoHead;
    ipSize, udpSize: Word;
    iphdrlen, pseudohdrlen, udphdrlen: Word;
    lpipHdr: pipHead;
    lpudpHdr: pudpHead;
    p, p0: PChar;
    Local: TSockAddrIn;
    Remote: TSockAddrIn;
    i, j, k: integer;
    begin
    inc(idt); // test
    // 功能:分片发送ip 分片包UDP协议
    Local.sin_family := AF_INET;
    Local.sin_addr.S_addr := inet_Addr(PChar(srcIP));
    Local.sin_port := htons(srcPort);Remote.sin_family := AF_INET;
    Remote.sin_addr.S_addr := inet_Addr(PChar(dstIP));
    Remote.sin_port := htons(dstPort);iphdrlen := sizeof(_ipHead);
    udphdrlen := sizeof(_udpHead);
    pseudohdrlen := sizeof(pseudoHdr);j := datalen div fraglen;
    if (datalen mod fraglen) = 0 then j := j - 1;
    for i := 0 to j do
    begin
        if datalen > (i + 1) * fraglen then k := fraglen + udpHdrLen
        else k := datalen - i * fraglen;
        ipSize := iphdrlen + udphdrlen + k;
        udpSize := ipSize - iphdrlen;
    // 初始化 IP 头
        ipHdr.ver_IHL := (4 shl 4) or (sizeof(ipHdr) div 4);
        ipHdr.serverType := 0; // IP type of service
        ipHdr.totalLen := htons(ipSize); // Total packet len
        ipHdr.ident := htons(idt); // Unique identifier: set to 0
        // Fragment offset field
        if i = 0 then ipHdr.flags_off := htons($2000) // 第一片
        else if i < j then ipHdr.flags_off := htons($2000 or (fraglen + udpHdrLen) * i) // 中间片
        else ipHdr.flags_off := htons((fraglen + udpHdrLen) * i); // 最后一片
        ipHdr.ttl := 128; // Time to live
        ipHdr.protocol := 17; // Protocol(UDP)
        ipHdr.ipchksum := 0; // IP checksum
        ipHdr.srcAddr := Local.sin_addr.S_addr; // Source address
        ipHdr.dstAddr := Remote.sin_addr.S_addr; // Destination address// 初始化 UDP 头
        udpHdr.srcPort := Local.sin_port;
        udpHdr.dstPort := Remote.sin_port;
        udpHdr.Length := htons(udpSize);
        udpHdr.checksum := 0;// 初始化 伪ip 头
        pseudoHdr.srcAddr := ipHdr.srcAddr;
        pseudoHdr.dstAddr := ipHdr.dstAddr;
        pseudoHdr.unused := 0;
        pseudoHdr.protocol := ipHdr.protocol;
        pseudoHdr.Length := udpHdr.Length;    p := buf + iphdrlen - pseudohdrlen;
        p0 := P; // 备份伪ip头指针p0,checksum 运算用
        move(pseudoHdr, p^, pseudohdrlen);
        inc(p, pseudohdrlen);
        lpudpHdr := pudpHead(p);
        move(udpHdr, p^, udphdrlen);
        inc(p, udphdrlen);
        move(data^, p^, k);
        inc(p, k);
        lpudpHdr^.checksum := checksum(p0, p - p0);
    // copy ip头;覆盖伪ip头
        p := buf;
        lpipHdr := pipHead(p);
        move(ipHdr, p^, iphdrlen);
        lpipHdr^.ipchksum := checksum(buf, iphdrlen); // ip头// Send the raw socket packet
        result := sendto(hsocket, buf, ipSize, 0, @Remote, SizeOf(Remote));
        if result = SOCKET_ERROR then
        begin
          str := 'sendto() failed: ' + IntToStr(WSAGetLastError);
          SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
          exit;
        end;end;
    result := datalen;
    end;
  • 相关阅读:
    android修改debug keystore文件使之和正式keystore sha1一致
    scrollView中可以自由滚动的listview
    android gradle的全局管理
    OpenGL学习笔记(三)
    OpenGL学习笔记(二)
    OpenGL学习笔记(一)
    Java编程代码规范中值得留意的地方
    mac上编译Android的arm64位ffmpeg
    入门程序员必读的10本经典书单
    [Android文档翻译]设备兼容性
  • 原文地址:https://www.cnblogs.com/moonwind/p/4523765.html
Copyright © 2020-2023  润新知