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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

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

Q&A

解決済

2回答

11270閲覧

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

izuki_y

総合スコア65

C

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

0グッド

0クリップ

投稿2016/11/08 15:06

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

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

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

C

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

とか

C

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

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

環境

  • Windows7 Professional x64
  • Cygwin 2.0.1
  • clang version 3.5.1

ソース

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> /* for strncpy */ 4 5#include <net/if.h> 6#include <sys/socket.h> 7#include <netinet/in.h> 8#include <arpa/inet.h> 9#include <errno.h> 10 11#include <sys/types.h> 12#include <sys/ioctl.h> 13 14#define ARPHRD_ETHER (1) /* Ethernet 10Mbps */ 15#define ETH_P_IP (0x800) 16#define ETH_P_ARP (0x0806) 17#define ETH_HLEN (6) /* MACアドレス長 */ 18#define ETH_PLEN (4) /* IPv4アドレス長 */ 19#define ARPOP_REQUEST (1) 20 21typedef unsigned char u_int8_t; // ISO C にあるらしい 22 23struct arphdr { 24 unsigned short int ar_hrd; /* Format of hardware address. */ 25 unsigned short int ar_pro; /* Format of protocol address. */ 26 unsigned char ar_hln; /* Length of hardware address. */ 27 unsigned char ar_pln; /* Length of protocol address. */ 28 unsigned short int ar_op; /* ARP opcode (command). */ 29}; 30 31struct ether_arp { 32 struct arphdr ea_hdr; /* fixed-size header */ 33 u_int8_t arp_sha[ETH_HLEN]; /* sender hardware address */// 送信元MACアドレス 34 u_int8_t arp_spa[ETH_PLEN]; /* sender protocol address */// 送信元IPアドレス 35 u_int8_t arp_tha[ETH_HLEN]; /* target hardware address */// 宛先MACアドレス( All 0 ) 36 u_int8_t arp_tpa[ETH_PLEN]; /* target protocol address */// 宛先IPアドレス(取得したIPv4アドレス) 37}; 38 39int send_arp() 40{ 41 struct ether_arp arpbody; 42 struct sockaddr_in sockaddr; 43 int arp_sock = 0; 44 long lReturn = 0; 45 struct ifreq ifr; 46 printf("send arp!!\n"); 47 48 // デバイスソケットを作成する 49// if ((arp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 50 if ((arp_sock = socket(AF_INET, SOCK_RAW, htons(ETH_P_IP))) < 0) { 51 printf("ioctl socket creation"); 52 exit(1); 53 } 54 55 ifr.ifr_addr.sa_family = AF_INET; 56 strncpy(ifr.ifr_name, "{E1205058-1BF3-4591-AA26-936B4AF08E1F}", IFNAMSIZ-1); 57 58 // 送信元MACアドレス 59 lReturn = ioctl(arp_sock, SIOCGIFHWADDR, &ifr); 60 memcpy(arpbody.arp_sha, ifr.ifr_hwaddr.sa_data, ETH_HLEN); 61 62 // 送信元プロトコルアドレス 63 lReturn = ioctl(arp_sock, SIOCGIFADDR, &ifr); 64 memcpy(&sockaddr, &(ifr.ifr_addr), sizeof(sockaddr)); 65 memcpy(arpbody.arp_spa, &(sockaddr.sin_addr), 4); 66 67 68 69 70 // 作成したソケットにread/writeして送受信する。 71 arpbody.ea_hdr.ar_hrd = htons(ARPHRD_ETHER); 72 arpbody.ea_hdr.ar_pro = htons(ETH_P_IP); /* ARP Protocol Number */ 73 74 arpbody.ea_hdr.ar_hln = ETH_HLEN; 75 arpbody.ea_hdr.ar_pln = ETH_PLEN; 76 arpbody.ea_hdr.ar_op = htons(ARPOP_REQUEST); 77 78 // 宛先MACアドレス 79 memset(arpbody.arp_tha, 0x00, ETH_HLEN); //arpbody.arp_tha 80 // 宛先IPアドレス 81 //inet_ntop(AF_INET, &tFromAddr.sin_addr, arpbody.arp_tpa, sizeof(arpbody.arp_tpa)); 82 inet_aton( "192.168.10.4", &arpbody.arp_tpa ); 83 84 85 memset(&sockaddr, 0x0, sizeof(sockaddr)); 86 sockaddr.sin_family = AF_INET; // AF_PACKET 87 sockaddr.sin_port = htons(ETH_P_ARP); 88 memset(&sockaddr.sin_addr, 0xff, ETH_HLEN); 89 90 lReturn = sendto(arp_sock, (char *)&arpbody, sizeof(arpbody), 0, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in)); 91 if(lReturn < 0){ 92 printf("Error! sendto %d\n", errno); 93 close(arp_sock); 94 return -1; 95 } 96 97 98 99 /* recv */ 100 while(1) { 101 char buf[256]; 102 memset(buf,0x0,sizeof(buf)); 103 int arp_size = recvfrom(arp_sock, buf, sizeof(buf), 0, NULL, NULL); 104 if(arp_size < 0) { 105 printf("errno: %d\n",errno); 106 if (errno == EAGAIN) { 107 /* まだ来ない。*/ 108 printf("MADA KONAI\n"); 109 } else { 110 perror("recv"); 111 break; 112 } 113 }else{ 114 115 /* 受信したデータはARPパケットなので、その形にキャストして情報にアクセスする */ 116 struct ether_arp *arppack = (struct ether_arp*) buf; 117 118 printf("arppack->arp_tha[0]:%x\n", arppack->arp_tha[0]); 119 printf("arppack->arp_tha[1]:%x\n", arppack->arp_tha[1]); 120 printf("arppack->arp_tha[2]:%x\n", arppack->arp_tha[2]); 121 printf("arppack->arp_tha[3]:%x\n", arppack->arp_tha[3]); 122 printf("arppack->arp_tha[4]:%x\n", arppack->arp_tha[4]); 123 printf("arppack->arp_tha[5]:%x\n", arppack->arp_tha[5]); 124 } 125 } 126 close(arp_sock); 127} 128 129 130 131 132int main(int argc, char **argv){ 133 printf("main start\n"); 134 send_arp(); 135 return 0; 136 137}

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

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/08 15:23

hiim

総合スコア1689

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

izuki_y

2016/11/17 13:30

回答ありがとうございます。 やはり存在しなさそうですね。 そもそもUDP/TCP通信は行っても、 わざわざデータリンク層からのフレーム通信を行う人はあんまり居ないですよね。 PF_SOCKETの値を直に設定すれば再現できるかと思いましたがそれすらも見つからなさそうなので 暫く他の回答者さんを待ってみる事にします。 貴重な情報ありがとうございました
guest

0

ベストアンサー

[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/09 03:41

ikedas

総合スコア4227

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

izuki_y

2016/11/17 13:37 編集

回答ありがとうございます。 libcapについて調べてみます。 SOCK_RAWでの送信は試してみたのですが、ソケット生成の時点でpermission errorになりました。 ドライバの担当者にラッパ関数を作ってもらう事で通信できるようになると返事を頂きました。 ドライバの下回りはLinuxで作っているらしいのでPF_SOCKETを使える環境下なのかもしれません。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問