Issue
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
Solution
Windows does not allow TCP packets over RAW sockets, as documented on MSDN:
https://learn.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.
Answered By - Remy Lebeau Answer Checked By - Marilyn (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.