ソースルーティング
IPのオプションを指定してLinuxで経路を指定してパケットを出す方法を調べてみた
設定方法
IPのオプションを指定する方法は以下の2通りがある
ソケット単位に指定する setsockoptでIP_OPTIONSを指定する
パケット単位で設定を変える sendmsgのstruct msghdr->msg_controlにIP_RETOPTのCMSGを設定する
今回はソケット単位に指定する方法を使用
ソース
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/udp.h> #include <linux/ip.h> void main() { unsigned char options[256] = {0}; options[0] = IPOPT_LSRR; // type int len = 11; options[1] = len; // len; options[2] = 4; // pointer struct in_addr addr; inet_aton("1.1.1.1", &addr); *((uint32_t*)(options + 3)) = addr.s_addr; inet_aton("2.2.2.2", &addr); *((uint32_t*)(options + 7)) = addr.s_addr; options[7] = IPOPT_NOOP; int sock = socket(AF_INET, SOCK_DGRAM, 0); if ( sock == -1 ) { perror("creat socket error\n"); exit(1); } if ( setsockopt(sock, SOL_IP, IP_OPTIONS, options, len) == -1 ) { perror("set ip options error\n"); exit(1); } struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(8080); inet_aton("3.3.3.3", &sin.sin_addr); char buf[] = "test"; int ret = sendto(sock, buf, sizeof(buf), 0, (struct sockaddr*)&sin, sizeof(sin)); printf("%d\n", ret); }
動作
ソースルーティングはoptionで指定されているものが送信先となる。 この場合1.1.1.1 => 2.2.2.2 => 3.3.3.3という経路になるので 送信先が1.1.1.1となる。 sendで指定されたものは送信先ではなく、経路の最後に追加される。
処理しているのはLinuxカーネルのnet/ipv4/ip_options.c:ip_options_compile周り
ルータの設定
デフォルトではLinuxをルータとして使用している場合ip_forwardを有効にしてもソースルーティングは有効にならない。
echo "1" > /proc/sys/net/ipv4/conf/all/accept_source_route
を実行して使用したいデバイスの
echo "1" > /proc/sys/net/ipv4/conf/<dev>/accept_source_route
sourceルーティングを有効にしておく必要がある