Ich studiere Socket-Programmierung mit C/C++ und ich denke, der beste Weg ist es, in sie einzutauchen. Ich kann Daten an den Socket senden, indem ich socket.h send() verwende, und möchte daher tiefer gehen, indem ich Netzwerkpakete herstelle.Crafting TCP/IP Pakete
Ich habe versucht, konnte aber immer noch nicht herausfinden, welcher Teil meiner Daten ungültig ist, wie ich Invalid argument errno 22. Das ist meine IP-Header in hex bin immer:
45 00 28 00
d4 31 00 00
ff 06 3c 6e
c0 a8 01 06
c0 a8 01 01
Und das ist mein TCP header:
00 50 00 50
00 00 00 00
00 00 00 00
50 02 16 d0
15 1b 00 00
Ich schätze alle Tipps.
NB: Ich lese beej.us und here für meine Studien.
Edit: Das ist mein Code:
struct pseudo_header {
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t tcp_length;
};
int main(int argc, char* argv[]) {
int sockfd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sockfd == -1) {
perror("Failed to create socket");
exit(1);
}
// Datagram to represent the packet
char datagram[4096];
memset(datagram, 0, 4096); // zero out the packet buffer
//Data part
char *data = datagram + sizeof(struct ip) + sizeof(struct tcphdr);
strcpy(data, "");
// some address resolution
char source_ip[32];
strcpy(source_ip, "192.168.1.6");
struct sockaddr_in sai;
sai.sin_family = AF_INET;
sai.sin_port = htons(80);
sai.sin_addr.s_addr = inet_addr("192.168.1.1");
cout << "sai.sin_addr.s_addr=" << sai.sin_addr.s_addr << endl;
//Fill in the IP Header
struct ip *iph = (struct ip *) datagram;
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr) + strlen(data);
iph->ip_id = htons(54321);
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_TCP;
iph->ip_sum = 0;
iph->ip_src.s_addr = inet_addr(source_ip);
iph->ip_dst.s_addr = sai.sin_addr.s_addr;
//Ip checksum
unsigned short checksum = csum((unsigned short *) datagram, iph->ip_len);
iph->ip_sum = checksum;
cout << "iph->ip_sum=" << checksum << endl;
unsigned char *pIph = (unsigned char *) datagram;
for (int i = 0; i < 20; i++) {
cout << setfill('0') << setw(2) << hex << (int) pIph[i] << " ";
if (i + 1 >= 4 && (i + 1) % 4 == 0) {
cout << endl;
}
}
//TCP Header
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof(struct ip));
struct pseudo_header psh;
tcph->th_sport = htons(80);
tcph->th_dport = htons(80);
tcph->th_seq = 0;
tcph->th_ack = 0;
tcph->th_off = 5;
tcph->th_flags = TH_SYN;
tcph->th_win = htons(5840); /* maximum allowed window size */
tcph->th_sum = 0;
tcph->th_urp = 0;
//Now the TCP checksum
psh.source_address = inet_addr(source_ip);
psh.dest_address = sai.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr) + strlen(data));
int psize = sizeof(struct pseudo_header) +
sizeof(struct tcphdr) +
strlen(data);
char *pseudogram = malloc(psize);
memcpy(pseudogram, (char*) &psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + strlen(data));
checksum = csum((unsigned short*) pseudogram, psize);
tcph->th_sum = checksum;
cout << "tcph->th_sum=" << checksum << endl;
unsigned char *pTcph = (unsigned char *) tcph;
for (int i = 0; i < 20; i++) {
cout << setfill('0') << setw(2) << hex << (int) pTcph[i] << " ";
if (i + 1 >= 4 && (i + 1) % 4 == 0) {
cout << endl;
}
}
//IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
perror("Error setting IP_HDRINCL");
exit(0);
}
struct sockaddr *pSa = (struct sockaddr *) &sai;
// Send the packet
if (sendto(sockfd, datagram, iph->ip_len, 0, pSa, sizeof(sai)) < 0) { // failed here
perror("sendto failed");
} else { //Data send successfully
printf("Packet Send. Length : %d \n", iph->ip_len);
}
return 1;
}
Gibt es einen Grund, warum Sie erstellen möchten, und Handle deine eigenen rohen Pakete? Wenn Sie nur Netzwerk-Programmierung lernen wollen, dann ist das nicht wirklich ein guter Anfang IMO. Erfahren Sie stattdessen, wie Sie die Standardprotokolle TCP und UDP mit den normalen Sockeln 'SOCK_STREAM' und' SOCK_DGRAM' verwenden. Dann, wenn Sie Ihren eigenen Netzwerk-Stack (aus irgendeinem masochistischen Grund) implementieren möchten, können Sie das tun, aber nehmen Sie es langsam, Schritt für Schritt, und *** beginnen an der Spitze ***. –
Wo * genau * findest du 'errno' auf 22 gesetzt? Bitte posten Sie einen Teil Ihres Codes, wo er fehlschlägt. –
Ja, es gibt einen Grund, warum ich rohe Pakete herstellen will. Ich möchte ein ICMP-Tunneling-Programm schreiben. – anon