今回はCでARPテーブルにエントリーを追加してみます。
鍵となるのは、ARPエントリーの情報をまとめたarpreq構造体と、そのエントリーをARPテーブルに登録するためのSIOCSARPです。ちなみにSIOCGARPでエントリー情報を取得できます。
ARPエントリーを新規追加するには、MACアドレス、IPアドレス、フラグ、インタフェースの4つを指定しなければいけません。その4つの情報をarpreq構造体に格納して、そのarpreq構造体をSIOCSARPで登録すれば追加完了です。
arpreq構造体は、/usr/include/linux/if_arp.hで定義されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* ARP ioctl request. */ struct arpreq { struct sockaddr arp_pa; /* protocol address */ struct sockaddr arp_ha; /* hardware address */ int arp_flags; /* flags */ struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ char arp_dev[16]; }; /* ARP Flag values. */ #define ATF_COM 0x02 /* completed entry (ha valid) */ #define ATF_PERM 0x04 /* permanent entry */ #define ATF_PUBL 0x08 /* publish entry */ #define ATF_USETRAILERS 0x10 /* has requested trailers */ #define ATF_NETMASK 0x20 /* want to use a netmask (only for proxy entries) */ #define ATF_DONTPUB 0x40 /* don't answer this addresses */ |
ソースコードはこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<errno.h> #include<sys/socket.h> #include<sys/ioctl.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/if_ether.h> #include<net/if_arp.h> #include<arpa/inet.h> #include<unistd.h> #include<linux/netdevice.h> #define HARDWARE_LEN 6 int set_arp(int soc, char *device, char *dest_ip, char *dest_mac); int set_arp(int soc,char *device, char *dest_ip, char *dest_mac) { struct arpreq arpreq; struct sockaddr_in *sin; uint8_t *hwaddr; memset(&arpreq, 0, sizeof(struct arpreq)); /*MACアドレスをフォーマット形式から数値に変換*/ hwaddr = malloc(HARDWARE_LEN); if(sscanf(dest_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", hwaddr, hwaddr+1, hwaddr+2, hwaddr+3, hwaddr+4, hwaddr+5)!=HARDWARE_LEN){ fprintf(stderr, "[-]ERROR: Invalid_MAC '%s'\n", dest_mac); return -1; } /*arpreq構造体にMACアドレスを格納*/ memcpy(arpreq.arp_ha.sa_data, hwaddr, HARDWARE_LEN); /*IPアドレスをフォーマット形式から数値に変換すると同時にarpreq構造体に格納*/ sin = (struct sockaddr_in *)&arpreq.arp_pa; sin->sin_family = AF_INET; if((inet_pton(AF_INET, dest_ip, &sin->sin_addr.s_addr))!=1){ fprintf(stderr, "[-]ERROR: Invalid_IP '%s'\n", dest_ip); return -1; } /*フラグの設定*/ arpreq.arp_flags = ATF_PERM | ATF_COM; /*新しいエントリーを追加するインタフェースを指定*/ memcpy(arpreq.arp_dev, device, sizeof(arpreq.arp_dev)-1); /*SIOCSARPで実際のARPテーブルにエントリーを追加*/ if(ioctl(soc, SIOCSARP, &arpreq)<0){ fprintf(stderr, "[-]ERROR: SIOCSARP\n"); return -1; } return 0; } /*main関数*/ int main(int argc, char *argv[]) { int soc; if(argc!=4){ fprintf(stderr, "[-]Usage:[%s] Interface, Dest_IP, Dest_MAC\n", argv[0]); return -1; } if((soc=socket(AF_INET, SOCK_DGRAM, 0))<0){ fprintf(stderr, "[-]ERRPR: Socket_Creation_Failed\n"); return -1; } if((set_arp(soc, argv[1], argv[2], argv[3]))!=0){ fprintf(stdout, "[-]ERROR: Set_ARP_Failed\n"); return -1; } fprintf(stdout, "[+]Set_ARP_Success: IP[%s], MAC[%s]\n", argv[2], argv[3]); close(soc); return 0; } |
実行結果は以下のようになります。
まずは、arpテーブルを表示させます。

プログラムを実行します。

実行後のarpテーブルを表示させます。実行時に指定したアドレスの対応表が追加されます。

ちなみにシャットダウンすれば、新規追加されたARPエントリーは消えます。
最後まで読んでいただきありがとうございます。