読者です 読者をやめる 読者になる 読者になる

φ(.. )メモシテオコウ gethostbyname(3) と gethostbyaddr(3)は古いらしいので

network

gethostbyname(3)のmanによると「gethostbyname*() と gethostbyaddr*() は過去のものである。」とあり、代わりにgetaddrinfo(3)とgetnameinfo(3)を使うようにとかかれているのでとりあえずめも。

ホスト名からIPアドレスを引く場合はgetaddrinfo(3)でIPアドレスからホスト名を引く場合はgetnameinfo(3)。

まずはgetaddrinfo(3)。関数プロトタイプはこれで、1番目の引数はホスト、2番目はポート。3番目のhintsはオプションでNULLを渡しても良いが、例えばIPv4のみ出調べたいなら構造体のメンバに値を設定する必要がある。最後の引数は結果を保存する変数。これはアドレスが複数返ってくる可能性があるので。連結リストが使われてている。

int getaddrinfo(const char *node, const char *service,
                const struct addrinfo *hints,
                struct addrinfo **res);

使い方はだいたいこの様な感じで。IPアドレスはresのai_addrをsockaddr_inへのポインタにキャストしてそこからsin_addr構造体のs_addrメンバ変数にセットされているのでinet_ntop(3)で文字列形式でIPアドレスを取得。

static void
host2ip(const char *target)
{
	struct addrinfo *result = NULL;
	struct addrinfo hints = { 0 };
	struct addrinfo *info = NULL;

	int ret = 0;
	
	hints.ai_socktype = SOCK_STREAM;

	ret = getaddrinfo(target, NULL, &hints, &result);
	if (ret != 0) {
		printf("[-]Error %s\n", gai_strerror(ret));
		exit(-1);
	}

	for (info = result; info != NULL; info = info->ai_next) {
		char buf[INET_ADDRSTRLEN] = { 0 };
		struct in_addr ia;
		ia.s_addr = ((struct sockaddr_in *)(info->ai_addr))->sin_addr.s_addr;
		inet_ntop(info->ai_family, &ia, buf, sizeof(buf));
		printf("%s -> %s\n", target, buf);
	}

	freeaddrinfo(result);

}

getaddrinfo()を使った場合、プログラム側でデータの解放処理をする必要があるので最後にfreeaddrinfo()を呼ぶのを忘れずに。

次のgetnameinfo(3)はgetaddrinfo(3)よりはシンプル。
一番目のsockaddr構造体にはsin_familyにプロトコルファミリー、sin_addrにIPアドレス(をバイナリ形式にしたもの)をセットする。
hostとかservは結果を保存するバッファでオプションなのでいらなければNULLを渡す。

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                char *host, size_t hostlen,
                char *serv, size_t servlen, int flags);

プロトコルファミリーにAF_INETを指定して名前を引くのはこんな形で。

static void
ip2host(const char *target)
{
	struct sockaddr_in sa = { 0 };
	char buf[NI_MAXHOST] = { 0 };
	int ret = 0;

	sa.sin_family = AF_INET;
	inet_pton(sa.sin_family, target, &sa.sin_addr);

	ret = getnameinfo((const struct sockaddr *) &sa, sizeof(sa), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
	if (ret != 0) { 
		printf("[-]Error %s\n", gai_strerror(ret));
		exit(-1);
	}

	printf("%s -> %s\n", target, buf);

}

getaddrinfo(3),getnameinfo(3)ともにエラーの場合は返り値をgai_strerror()に渡すとエラーメッセージを返してくれるのでそれを使えます。

これで実際に試してみるとこのようになります。

[masami@saga:~/codes]$ ./a.out -h yahoo.co.jp
yahoo.co.jp -> 203.216.243.240
yahoo.co.jp -> 124.83.187.140
[masami@saga:~/codes]$ dig yahoo.co.jp

; <<>> DiG 9.9.3-rl.13207.22-P2-RedHat-9.9.3-5.P2.fc19 <<>> yahoo.co.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41975
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;yahoo.co.jp.                   IN      A

;; ANSWER SECTION:
yahoo.co.jp.            12      IN      A       203.216.243.240
yahoo.co.jp.            12      IN      A       124.83.187.140

;; Query time: 1 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Tue Sep 17 19:26:15 JST 2013
;; MSG SIZE  rcvd: 61

使ったソースはgistにあります。