質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C

    4534questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語でARPパケットのやり取りを行いたい(C言語によるフレーム送信のやり方)

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,112

izuki_y

score 47

いつもお世話になっております。
件名の事について質問があります。

現在ARPパケットを取得するプログラムを作成しています。
ARPパケットの通信を行いたいのですが上手くいきません。

上手くいきませんと言うかよく分かりません。
ネット上のサンプルを見るとC言語でARPを実現させるには

if((iSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0 ){
  perror("socket");
  exit(0);
}

とか

if((sockA = socket((AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP))) < 0 ){
  perror("socket");
  exit(0);
}

など書かれていますが、そもそも低レイヤーを扱うAF_PACKET(PF_PACKET)の定義がどこにもありません。
自分でマクロ定義しようとしましたが AF_PACKET(PF_PACKET) の値の情報もありません。
第一引数を AF_INET にしてみましたがエラーになります。

 環境

+ Windows7 Professional x64
+ Cygwin 2.0.1
+ clang version 3.5.1

 ソース

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for strncpy */

#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/ioctl.h>

#define ARPHRD_ETHER    (1)     /* Ethernet 10Mbps              */
#define ETH_P_IP        (0x800)
#define ETH_P_ARP       (0x0806)
#define ETH_HLEN        (6)    /* MACアドレス長 */
#define ETH_PLEN        (4)    /* IPv4アドレス長 */
#define ARPOP_REQUEST   (1)

typedef unsigned char u_int8_t; // ISO C にあるらしい

struct arphdr {
    unsigned short int ar_hrd;  /* Format of hardware address.  */
    unsigned short int ar_pro;  /* Format of protocol address.  */
    unsigned char  ar_hln;      /* Length of hardware address.  */
    unsigned char  ar_pln;      /* Length of protocol address.  */
    unsigned short int ar_op;   /* ARP opcode (command).  */
};

struct  ether_arp {
    struct arphdr ea_hdr;        /* fixed-size header */
    u_int8_t arp_sha[ETH_HLEN]; /* sender hardware address */// 送信元MACアドレス
    u_int8_t arp_spa[ETH_PLEN];    /* sender protocol address */// 送信元IPアドレス
    u_int8_t arp_tha[ETH_HLEN]; /* target hardware address */// 宛先MACアドレス( All 0 )
    u_int8_t arp_tpa[ETH_PLEN];    /* target protocol address */// 宛先IPアドレス(取得したIPv4アドレス)
};

int send_arp()
{
    struct ether_arp arpbody;
    struct sockaddr_in sockaddr;
    int arp_sock = 0;
    long lReturn = 0;
    struct ifreq ifr;
    printf("send arp!!\n");

    // デバイスソケットを作成する
//     if ((arp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    if ((arp_sock = socket(AF_INET, SOCK_RAW, htons(ETH_P_IP))) < 0) {
        printf("ioctl socket creation");
        exit(1);
    }

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, "{E1205058-1BF3-4591-AA26-936B4AF08E1F}", IFNAMSIZ-1);

    // 送信元MACアドレス
    lReturn = ioctl(arp_sock, SIOCGIFHWADDR, &ifr);    
    memcpy(arpbody.arp_sha, ifr.ifr_hwaddr.sa_data, ETH_HLEN);

    // 送信元プロトコルアドレス
    lReturn = ioctl(arp_sock, SIOCGIFADDR, &ifr);
      memcpy(&sockaddr, &(ifr.ifr_addr), sizeof(sockaddr));
       memcpy(arpbody.arp_spa, &(sockaddr.sin_addr), 4);




    // 作成したソケットにread/writeして送受信する。
    arpbody.ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
    arpbody.ea_hdr.ar_pro = htons(ETH_P_IP);    /* ARP Protocol Number */

    arpbody.ea_hdr.ar_hln = ETH_HLEN;
    arpbody.ea_hdr.ar_pln = ETH_PLEN;
    arpbody.ea_hdr.ar_op  = htons(ARPOP_REQUEST);

    // 宛先MACアドレス
    memset(arpbody.arp_tha, 0x00, ETH_HLEN); //arpbody.arp_tha
    // 宛先IPアドレス
    //inet_ntop(AF_INET, &tFromAddr.sin_addr, arpbody.arp_tpa, sizeof(arpbody.arp_tpa));
    inet_aton( "192.168.10.4", &arpbody.arp_tpa );


    memset(&sockaddr, 0x0, sizeof(sockaddr));
    sockaddr.sin_family = AF_INET;    // AF_PACKET
    sockaddr.sin_port = htons(ETH_P_ARP);
    memset(&sockaddr.sin_addr, 0xff, ETH_HLEN);

    lReturn =  sendto(arp_sock, (char *)&arpbody, sizeof(arpbody), 0, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in));
    if(lReturn < 0){
        printf("Error! sendto %d\n", errno);
        close(arp_sock);
        return -1;
    }



    /* recv */    
    while(1) {
        char buf[256];
        memset(buf,0x0,sizeof(buf));
        int arp_size = recvfrom(arp_sock, buf, sizeof(buf), 0, NULL, NULL);
        if(arp_size < 0) {
            printf("errno: %d\n",errno);
            if (errno == EAGAIN) {
                /* まだ来ない。*/
                printf("MADA KONAI\n");
            } else {
                perror("recv");
                break;
            }
        }else{

            /* 受信したデータはARPパケットなので、その形にキャストして情報にアクセスする */
            struct ether_arp *arppack = (struct ether_arp*) buf;

            printf("arppack->arp_tha[0]:%x\n", arppack->arp_tha[0]);
            printf("arppack->arp_tha[1]:%x\n", arppack->arp_tha[1]);
            printf("arppack->arp_tha[2]:%x\n", arppack->arp_tha[2]);
            printf("arppack->arp_tha[3]:%x\n", arppack->arp_tha[3]);
            printf("arppack->arp_tha[4]:%x\n", arppack->arp_tha[4]);
            printf("arppack->arp_tha[5]:%x\n", arppack->arp_tha[5]);
        }
    }
    close(arp_sock);
}




int main(int argc, char **argv){
    printf("main start\n");
    send_arp();
    return 0;

}

取り急ぎこんな感じのソースを書いてみましたが、ちょっと自分でももう一度推敲し直そうと思います。
質問の内容とは乖離しますが、低レイア層の通信の仕方を教えてください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

[1] の29章「Datalink Access」に解説がありますが、パケットをデータリンク層で直接読む方式としては、BSDのBSD Packet Filter (BPF)、SVr4のDatalink Provider Interface (DLPI)、LinuxのPF_SOCKETがあるそうです。Cygwinがどれに当たるのかは書いてないのでわかりませんが、これらのラッパとしてlibpcapなどがあるとのこと。

libpcapはCygwinでも使えるようです。また、パケットをデータリンク層で投げるほうは、普通にSOCK_RAWでできそうですね。

  • 同書にはlibpcapを使った詳細な解説つきのサンプルプログラムが載っています。
  • あと、arpingのソースもCygwin用のコードを含んでいます。やはりlibpcapを使っているようです。

参考になれば。


[1] W. Richard Stevens et al (2009). “Unix Network Programming: Volume 1: The Sockets Networking API, 3rd Edition”. Addison Wesley.
良書です。おすすめは第1巻の第3版 (日本語版は出ていない)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/15 00:10 編集

    回答ありがとうございます。

    libcapについて調べてみます。
    SOCK_RAWでの送信は試してみたのですが、ソケット生成の時点でpermission errorになりました。

    ドライバの担当者にラッパ関数を作ってもらう事で通信できるようになると返事を頂きました。
    ドライバの下回りはLinuxで作っているらしいのでPF_SOCKETを使える環境下なのかもしれません。

    本当にありがとうございました。

    キャンセル

+1

cygwinでのソケット通信はやった事がないので不確情報ですが、検索すると
古い情報ですが、cygwinのソケットはAF_PACKETをサポートしていない
http://cygwin.cygwin.narkive.com/2euIqwLl/undefined-ifr-ifindex-problem
Linuxでやるべきだとか

答えは返ってきていないが
https://www.zhihu.com/question/37042290
cygwinではAF_PACKETをサポートしてないの?
という書き込みがみられます。

cygwinはlinuxライクではあるけどやはりwindowsという事で難しいのかもしれません(不確情報ですのであくまでふと思った位のレベルですが)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/17 22:30

    回答ありがとうございます。
    やはり存在しなさそうですね。

    そもそもUDP/TCP通信は行っても、
    わざわざデータリンク層からのフレーム通信を行う人はあんまり居ないですよね。

    PF_SOCKETの値を直に設定すれば再現できるかと思いましたがそれすらも見つからなさそうなので
    暫く他の回答者さんを待ってみる事にします。

    貴重な情報ありがとうございました

    キャンセル

同じタグがついた質問を見る

  • C

    4534questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。