简体   繁体   中英

How to send tcp packets using raw sockets in winsock?

I'm trying to make a client which can send custom packets to a server using raw sockets. I've had success with udp packets but when I try to switch to tcp ones, wireshark doesnt catch anything. I have read that tcp data cannot be shared on raw sockets but I have seen people implementing that in linux. Is the idea of sending tcp packets over raw sockets even correct? And if it is, do I still need to use connect() method in the client code for tcp protocol?

Here's the code I've wrote (works fine with udp packets)

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iostream>
#include <string>

#pragma comment(lib, "Ws2_32.lib")

#define PORT 9090

using namespace std;

// custom headers

struct tcpheader {
    unsigned short int th_sport;
    unsigned short int th_dport;
    unsigned int th_seq;
    unsigned int th_ack;
    unsigned char th_x2 : 4, th_off : 4;
    unsigned char th_flags;
    unsigned short int th_win;
    unsigned short int th_sum;
    unsigned short int th_urp;
}; /* total tcp header length: 20 bytes (=160 bits) */

struct udphdr
{
    unsigned short udp_sport;
    unsigned short udp_dport;
    unsigned short udp_len;
    unsigned short udp_sum;
};

struct ipheader {
    unsigned char ip_hl : 4, ip_v : 4; /* this means that each member is 4 bits */
    unsigned char ip_tos;
    unsigned short int ip_len;
    unsigned short int ip_id;
    unsigned short int ip_off;
    unsigned char ip_ttl;
    unsigned char ip_p;
    unsigned short int ip_sum;
    unsigned int ip_src;
    unsigned int ip_dst;
}; /* total ip header length: 20 bytes (=160 bits) */

// checksum calculator

uint16_t
checksum(uint16_t* addr, int len)
{
    int count = len;
    register uint32_t sum = 0;
    uint16_t answer = 0;

    while (count > 1) {
        sum += *(addr++);
        count -= 2;
    }

    if (count > 0) {
        sum += *(uint8_t*)addr;
    }

    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }

    answer = ~sum;

    return (answer);
}


int main() {

    WSADATA ws;
    char datagram[4096];
    int bOpt = 1;

    // Setting up the enviornment for sockets

    if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) {
        cout << "WSAStartup() failed: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    // Creating a raw socket

    SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

    if (s == INVALID_SOCKET) {
        cout << "WSASocket() failed: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    // definfing the ip and tcp headers

    struct ipheader* iph = (struct ipheader*)datagram;
    // struct udphdr* udph = (struct udphdr*) (datagram + sizeof(struct ipheader));
    struct tcpheader* tcph = (struct tcpheader*)(datagram + sizeof(struct ipheader));
    
    string str = "Hello Server, What's running?";
    char* msg = const_cast<char*> (str.c_str());

    memcpy(datagram + sizeof(struct ipheader) + sizeof(struct udphdr), msg, sizeof(str));
    struct sockaddr_in sendTo;

    sendTo.sin_family = AF_INET;
    sendTo.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &sendTo.sin_addr);
    
    // memset(datagram, 0, sizeof datagram);

    // filling the packet : setting fields of headers

    // ip header

    iph->ip_hl = 5;
    iph->ip_v = 4;
    iph->ip_tos = 0;
    iph->ip_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
    iph->ip_id = 1;
    iph->ip_off = 0;
    iph->ip_ttl = 255;
    iph->ip_p = 6;
    iph->ip_sum = 0;
    inet_pton(AF_INET, "127.0.0.1", &iph->ip_src);
    iph->ip_dst = sendTo.sin_addr.s_addr;

    // udp header

    // udph->udp_sport = htons(1234);
    // udph->udp_dport = htons(PORT);
    // udph->udp_len = sizeof(struct udphdr);
    // udph->udp_sum = 0;

    // tcp header

    tcph->th_sport = htons(1234);
    tcph->th_dport = htons(PORT);
    tcph->th_seq = rand();
    tcph->th_ack = 0;
    tcph->th_x2 = 0;
    tcph->th_off = 0;
    tcph->th_flags = 2; // SYN 
    tcph->th_win = htons(65535);
    tcph->th_sum = 0;
    tcph->th_urp = 0;

    // calculate checksum

    // udph->udp_sum = checksum((unsigned short*)&udph, sizeof(struct udphdr));
    iph->ip_sum = checksum((unsigned short*)&iph, sizeof(struct ipheader));


    // setting socket option {IP_HDRINCL} for choosing custom ip header instead of kernel header
    
    if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&bOpt, sizeof(bOpt)) == SOCKET_ERROR) {
        cout << "setsockopt(IP_HDRINCL) failed: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    while (1) {
        int val = sendto(s, datagram, sizeof(datagram), 0, (sockaddr*)&sendTo, sizeof(sendTo));
        if (val == -1) {
            cout << "failed to send packet: " << WSAGetLastError() << endl;
            WSACleanup();
            return -1;
        }
        cout << val<<" ";
        Sleep(1000);
    }


    return 0;
} 

I tried various comninations of protocols in socket like IPPROTO_RAW, IPPROTO_TCP, IPPROTO_IP but nothing seems to work with tcp packets

Windows does not allow TCP packets over RAW sockets, as documented on MSDN:

https://docs.microsoft.com/en-us/windows/win32/winsock/tcp-ip-raw-sockets-2

On Windows 7, Windows Vista, Windows XP with Service Pack 2 (SP2), and Windows XP with Service Pack 3 (SP3), the ability to send traffic over raw sockets has been restricted in several ways:

  • TCP data cannot be sent over raw sockets.

  • ...

Linux does not have the same restriction that Windows does.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM