Rubyで自分のIPアドレスを知るってのを見た。元ネタの解説によると、アドレスやポート番号がダミーのUDPソケットを作成してconnect()すると、getsockname()で自分のアドレスが取得できるというもの。
connectのマニュアルページによると、UDPソケットをconnectすると特に何もパケットが送出されず、そのソケットのデフォルトのパケット送信先/唯一の受信先となるっていう仕様があるとのことで、これを利用しているらしい。
てな訳で、C言語でこれを実装してみた。記述が面倒だけど、実質的に関数側が求める仕様に合わせて書いてるだけ。
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc,char *argv[]) { int fd; struct sockaddr_in dst_addr={0}; struct sockaddr_in src_addr={0}; socklen_t addrlen; char str[16]; fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); dst_addr.sin_family=AF_INET; dst_addr.sin_port=htons(7); inet_aton("128.0.0.0",&dst_addr.sin_addr); connect(fd,(struct sockaddr *)&dst_addr,sizeof(dst_addr)); addrlen=sizeof(src_addr); getsockname(fd,(struct sockaddr *)&src_addr,&addrlen); inet_ntop(AF_INET,&src_addr.sin_addr,str,sizeof(str)); printf("%s\n",str); close(fd); return 0; }
追記:@saltheads氏のRuby版の元ネタとなったNeoCat氏のPerl版のさらに元ネタがリンク切れだったので見てなかったんだけど、ふとインターネットアーカイブで見れるんじゃないかと思って見てみたら、SHIROYAMA Takayuki氏がC言語で書かれていた(汗)
まあ、2001年の投稿なので記述が若干古いけど、基本的には今回自分で書いたものと同じだった。ただ、BSD系で必要なincludeと、相手と自分のアドレスを格納するのに同じ構造体使ってたり、構造体の初期化をしていなかった部分を元ソースを見て気になったので修正した。