2017-02-02 11 views
0

私はC/C++でソケットプログラミングを研究しており、最良の方法はそれに潜んでいると思います。 socket.h send()を使用してデータをソケットに送信することができます。したがって、ネットワークパケットを作成することによってより深く行きたいと思います。Crafting TCP/IP Packets

私が試したが、それでも私は無効な引数のエラー番号22を取得していますので、これは六角の私のIPヘッダで、無効である私のデータのどの部分を見つけ出すことができませんでした:

45 00 28 00 
d4 31 00 00 
ff 06 3c 6e 
c0 a8 01 06 
c0 a8 01 01 

そして、これは私のTCPでありますヘッダー:

00 50 00 50 
00 00 00 00 
00 00 00 00 
50 02 16 d0 
15 1b 00 00 

すべてのヒントをありがとうございます。

注意:私の研究ではbeej.ushereを読んでいます。

編集:これは私のコードです:あなたのIPv4ヘッダで

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; 
} 
+0

作成したい理由があるとあなた自身の生のパケットを扱う?ネットワークプログラミングを学びたいだけなら、それは本当に良いスタートIMOではありません。代わりに、標準の 'SOCK_STREAM'と' SOCK_DGRAM'ソケットを使って、標準のTCPとUDPプロトコルを使う方法を学んでください。次に、あなた自身のネットワークスタックを実装したい場合(いくつかのマジコスティックな理由で)、あなたはそれを行うことができますが、一度に1ステップずつ遅くしてください。 –

+0

*正確に* 'errno'が22に設定されていますか?失敗したコードの一部を投稿してください。 –

+0

はい、私は生のパケットを作りたい理由があります。 ICMPトンネリングプログラムを書いてみたい。 – anon

答えて

2

45 00[28 00] 
d4 31 00 00 
ff 06 3c 6e 
c0 a8 01 06 
c0 a8 01 01 

は、あなたのパケット長10240(0x2800)ですか?

本当に40(0x0028)ではないですか?

45 00[00 28] 
d4 31 00 00 
ff 06[64 46] // checksum updated 
c0 a8 01 06 
c0 a8 01 01 

EDIT:あなたのコードを掲示した今 ...

あなたが交換する必要があります。

iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr) + strlen(data); 

によって:

iph->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + strlen(data)); 
+0

これに冗長性を追加するだけで、ヘッダーのフィールドは**ビッグエンディアン**です。つまり、マルチバイトフィールドの場合、最上位バイトが先頭です。 –

+0

リファレンスするには、パケット内のすべての整数は**ネットワークバイトオーダー**です。マルチバイトのデータをネットワークに入れているときは、常に** host **から** network **へのバイトオーダーを変換する必要があります。つまり、** h **〜** n ** s()関数が行います。 –

+0

私はバイトオーダーが間違っていると思っていますが、私はまだwikiで書かれた違いを理解しようとしています。私のホストマシン+ cygwinはLEを使っています。ちょうど不思議なことに、フラグフィールドとオフセットフィールドは1バイト(3ビットと13ビット)未満です。どのように構造化する必要がありますか?それらは一緒に2バイトとみなされるべきですか? – anon

関連する問題