• ベストアンサー

アドレスの比較について

こんにちは。質問させてもらいます。 pcap.hを使って、取得したパケットの送信元アドレスと送信先アドレスを比較させて、違うアドか同じアドかを判断したいと考えています。 しかし、送信元アドレスと送信先アドレスが明らかに違うのに、同一だと判断してしまいます。原因を教えてもらえないでしょうか。 ipアドレスを格納する構造体は struct ip { struct in_addr ip_src, ip_dst; }; としました。 ↓が試した方法です。 1.inet_ntoaの値をそのまま比較 if ( inet_ntoa(ip->ip_src) == inet_ntoa(ip->ip_dst) ) { printf("\nアドレスいっしょ\n"); //↓はアドレスが違っているかどうか確認 printf("src:%s\n",inet_ntoa(ip->ip_src)); printf("dst:%s\n",inet_ntoa(ip->ip_dst)); } else { printf("\nアドレス違う\n"); } 2.strcmpを使う if ( strcmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst)) == 0) { printf("\nアドレスいっしょ\n"); printf("src:%s\n",inet_ntoa(ip->ip_src)); printf("dst:%s\n",inet_ntoa(ip->ip_dst)); } else { printf("\nアドレス違う\n"); } どちらでやってもアドレスは同じと判断してしまいます。printfで確認するときっちり違うアドが表示されるのに・・何故? きちんとアドレスを比較してくれるようにif文の中身を変えたいです。 ご助力お願いできますか。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★アドアイス >inet_ntoa の戻り値を free しないのにメモリリークしないことを不思議に…  ↑  不思議じゃないです。  C言語の標準関数でも内部に static なバッファを使って  戻り値を返す関数が沢山あります。  (strtok、gmtimeなどなど) 正しいサンプル: char srcBuff[ 32 ]; char dstBuff[ 32 ]; strcpy( srcBuff, inet_ntoa(ip->ip_src) ); strcpy( dstBuff, inet_ntoa(ip->ip_dst) ); if ( !strcmp(srcBuff,dstBuff) ){  printf("\nアドレスいっしょ\n");  //↓はアドレスが違っているかどうか確認  printf("src:%s\n", srcBuff );  printf("dst:%s\n", dstBuff ); } else{  printf("\nアドレス違う\n"); } 注意事項: マルチスレッド内で inet_ntoa のような関数を 複数のスレッドから呼び出すときには排他処理を行って下さい。 排他処理をしないと正しく変換(取得)出来ません。 今回の質問は良くある間違いです。 今後、staticな戻り値に注意しましょう。 http://www.geekpage.jp/programming/winsock/tips-inet_ntoa.php http://www.geekpage.jp/programming/winsock/tips-gethostbyname.php

mandly
質問者

お礼

ご回答有難う御座います。 分かりやすいサンプルを添えて頂いた事感謝します。 末尾のサイトも有難く参考にさせて頂きます。

その他の回答 (3)

  • GOOD-Fr
  • ベストアンサー率32% (83/256)
回答No.4

>>inet_ntoa の戻り値を free しないのにメモリリークしないことを不思議に… > 不思議じゃないです。 ちょっと話が難しすぎたかな・・・。 今回の質問者は、関数を呼び出したら毎回違うアドレスが返ってくる、と思ってプログラムを組んでいたわけですよね。それなら、free する責任は普通に考えて呼び出し側にあることになります。ところが自分では free してないのですから、メモリリークの可能性があることにすぐに気がつかなければなりません。 逆に、ちゃんとわかっている人なら「戻り値を返す関数が沢山あります」と言えるでしょう。こういう人は、ご指摘のように「排他処理をしないと正しく変換(取得)出来ません」というところまで、先回りして考えることができるわけです。あるべき姿ですね。 こういうベテランの人が「不思議じゃない」と思うことと、質問者が自身のプログラムを疑問に思わないことはまったくレベルが違う話です。 呼び出された関数がその内部で領域確保してくれてそのポインタを返す仕様は誤りではありませんが、呼び出した側がなにも考えずにそのポインタを捨てるのは誤り(要するに「よろしくない」)です。今回、質問者は前者の仕様だと考えて関数を呼び出し、後者のようにプログラムを組んでいるわけで、一貫性がありません。指摘されないとこの祖語に気がつかないようでは先が思いやられる、という意味です。 「サンプルなので free は省略しました」ということなら、仕様を誤って理解していますし、「free は忘れていました」ということなら、「誰が free するのか常に考えてプログラムしましょう」ということになります。どちらにしても、問題ですよね。

mandly
質問者

お礼

ご回答有難う御座います。 ご忠告は真摯に受け止めさせて頂きます。

  • GOOD-Fr
  • ベストアンサー率32% (83/256)
回答No.2

すでに正しい回答が出ているようですね。 inet_ntoa の戻り値が char * になっていて、呼び出し側からはリターン用のアドレスを引き渡していないことに気がつけば、こういう間違いはしないはずです。 というか、inet_ntoa の戻り値を free しないのにメモリリークしないことを不思議に思わないようでは、この先、「気分しだいで動いたり動かなかったり」のプログラムを量産することになるでしょう。この種のバグはデバッガでもなかなかとれないですよ。 これは指摘しなくても気が付いていると信じたいですが > アドレスは同じと判断してしまいます アドレスを比較しても文字列が等しいかどうかは判定できないと思います。 さらに余談ですが > if ( strcmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst)) == 0) 今回はあまり関係ありませんが、この書き方だとコンパイラが変わると動作が変わるかもしれませんね。

回答No.1

inet_ntoa関数は内部的に持っているchar型配列の先頭ポインタを返すような 仕様になっているのではないでしょうか? (inet_ntoaの戻り値をfreeするような記述があれば違いますが。) となると当然どんな引数を与えても同じ値が返ってきてしまいます。 また、strcmpを使う場合必ず同じになってしまうでしょう。 よって、戻り値の値をそのまま比較せず、一度char型配列に格納してから strcmpで比較するようにすれば良いでしょう。

mandly
質問者

お礼

ご回答有難うございます。参考になりました。

関連するQ&A

  • IPアドレスを配列に代入する方法。

    パケットモニタリング(tcpdumpみたいなもの)でIPアドレスを取得するプログラムがあるのですが、IPアドレスを配列に代入することが出来ません。 パケットモニタリングのソース void print_ip(struct ip *ip) { printf("| Source IP Address: %15s|\n", inet_ntoa(*(struct in_addr *) &(ip->ip_src))); /* ループ */ 実行画面 | Source IP Address: 12.34.56.78 | | Source IP Address: 34.56.78.09 | ・ ・ というふうにどんどん取得、表示していく このIPアドレス inet_ntoa(*(struct in_addr *) &(ip->ip_src))); を配列に代入していきたいのですが上手くいきません。一応自分でやってみたのですが、 void print_ip(struct ip *ip) { int *pa[2048]; static int i = 1; printf("| Source IP Address: %15s|\n", inet_ntoa(*(struct in_addr *) &(ip->ip_src))); i++; pa[i] = (int *)&(ip->ip_src); printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i])); if (i == 10) { for (i = 1; i < 10; i++) { printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i])); }} } という風にaddres[1]から順にどんどんIPアドレスを格納しようとしたんですがaddres[1]からaddres[10]まで表示するときに全部addres[10]に代入されているIPアドレスが表示されてしまいます。 おそらく配列にIPアドレスが上手く格納できてないんだと思うのですが。C言語初心者なので誰かご教授していただけないでしょうか? 宜しくお願いします。 OSはLinuxです。

  • for文が機能しません。どなたか原因を指摘して頂けますか。

    こんにちは。質問させて頂きます。 pcap.hで、「リスト構造に格納された送受ID・ポート」と、「キャプチャされたパケットの送受ID・ポート」を順に比較していって、同じであれば同一の通信フローとみなす、といったプログラムを作っています。 しかし、何故かfor文自体が機能せず、for文の中のprintf文が全く表示されないところをみると、for文をスルーしてしまっているようです。for文の中身の記述がおかしいのか、条件記述がおかしいのかのどちらかだとは思うのですが特定できません。 皆さんのお力をお貸し頂けないでしょうか。 以下がプログラムの一部です。 //ID・ポートを含んだリスト構造体作成 struct list { struct in_addr src, dst; u_short sport; u_short dport; struct list *next; }; //キャプチャされるパケットのID・ポート情報を記録する構造体 struct new_capture { struct in_addr new_src, new_dst; u_short new_sport; u_short new_dport; }; ループバック関数(){ //キャプチャされたパケット情報を構造体に写す struct new_capture nc; nc.new_dport = tcp->th_dport; nc.new_sport = tcp->th_sport; nc.new_src = ip->ip_src; nc.new_dst = ip->ip_dst; //リスト構造体の先頭と、ループさせるためのポインタを宣言 struct list flow_head; struct list *looplist; //問題のfor文 //looplistを利用して、キャプチャされたパケット情報と //リスト構造体に格納された情報とを比較する //同一ならばそれでbreak、全ての構造体と相違ならば //構造体の末端に新たに追加する for (looplist = &flow_head; looplist ; looplist = looplist->next) { if (inet_ntoa(looplist->src) == inet_ntoa(nc.new_src)) { if (inet_ntoa(looplist->dst) == inet_ntoa(nc.new_dst)) { if (looplist->sport == nc.new_sport) { if (looplist->dport == nc.new_dport) { printf ("送受アド、送受ポート同一"); break; } } } } else if (looplist->sport == nc.new_dport) { if (looplist->dport == nc.new_sport) { if (inet_ntoa(looplist->dst) == inet_ntoa(nc.new_src)) { if (inet_ntoa(looplist->src) == inet_ntoa(nc.new_dst)) { printf ("送受アド、送受ポート同一逆順"); break; } } } } else { printf ("同一ではない"); } } //通信フロー数を1増やし、リスト構造体にIDとポートを追加する if (looplist == NULL) { flow_counts++; printf ("通信フロー追加:%d\n", flow_counts); looplist = (struct list *) malloc (sizeof (struct list));   looplist->dport = nc.new_dport; looplist->sport = nc.new_sport; looplist->src = nc.new_src; looplist->dst = nc.new_dst; } free(looplist); return; } 上のlooplistにアドレスを代入しているはずなのに、ずぅ~っとNULLになっているらしく、for文が終わった後のif文が常に機能するようになってしまっています。 for文が機能しないのは何故なのか。 looplistがずっとNULLなのは何故なのか。 この二つが解決出来ればなんとか出来ると思うのですが力不足でそれに及びません。何か気が付かれた事等ありましたらご教授頂けないでしょうか。どうぞよろしくお願いします。

  • getaddrinf()で取得したIPアドレス表示

    お世話になります。 C言語でソケット通信の勉強中です。 CentOS6.4を使っています。 LIST1は、 IPアドレスではなくホスト名がコマンド引数で渡されたとき、 getaddrinfo()でIPアドレスを取得して、 sendto()でサーバにメッセージを送信するだけの、 クライアントのプログラムです。 このLIST1のudp通信自体は上手くいくのですが、 終わりの方で、 getaddrinfo()で取得したIPアドレスを inet_ntoa()を使って文字列表示しようとすると、 セグメンテーション違反です (コアダンプ)となってしまいます。 inet_ntoa()の引数が疑わしく、 いろいろ渡し方を変えたり、参照方法を変えたりしてみたのですが、、 なかなか解決しません。 ちゃんと、192.168.12.1とか表示するにはどうすれば良いでしょうか? ■LIST1 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> int main(int argc,char *argv[]){ int sock; struct addrinfo hints,*res; int n; int err; if(argc != 2){ fprintf(stderr,"Usage : %s dst \n",argv[0]); return 1; } /* IP アドレス表記+ホスト名両方に対応 */ memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPV4 IPV6 両方に対応 */ hints.ai_socktype = SOCK_DGRAM; err = getaddrinfo(argv[1],"12345",&hints,&res); if(err != 0){ perror("getaddrinfo"); printf("getaddrinfo %s\n",strerror(errno)); printf("getaddrinfo : %s \n",gai_strerror(err)); return 1; } sock = socket(res->ai_family,res->ai_socktype,0); if(sock < 0){ perror("socket"); return 1; } { const char *ipverstr; switch (res->ai_family){ case AF_INET: ipverstr = "IPv4"; break; case AF_INET6: ipverstr = "IPv6"; break; default: ipverstr = "unknown"; break; } printf("ipverstr = %s\n ",ipverstr); } n = sendto(sock,"HELLO",5,0,res->ai_addr,res->ai_addrlen); //n = sendto(sock,"HELLO", 5, 0,(struct sockaddr *)addr, sizeof(addr)); if(n<1){ perror("sendto"); { } return 1; } printf("############ finish !! #######\n"); close(sock); freeaddrinfo(res); struct sockaddr_in *addr; addr = (struct sockaddr_in *)res->ai_addr; printf("inet_ntoa(in_addr)sin = %s\n",inet_ntoa((struct in_addr)addr->sin_addr)); return 0; }

  • セグメンテーション違反

    C言語でネットワークを流れるパケットの取得&解析を行っているのですが、実行時にセグメンテーション違反と出てしまい、困っています。デバッグオプションをつけてやってみたところ、プログラムが中断されたところは分かったのですが、どこが悪いのか分かりません。どなたかあやしいところがありましたらお教え下さい。 OSはLinuxでコンパイラはgccです。 void udp_scanport(struct ip *ip, struct udphdr *udp) { static struct in_addr *ipaddr[1024]; static int i = -1; static int udp_count[1024]; struct in_addr *inwk; static u_short udp_port[1024]; int u = 0; int k = 0; i++; inwk = (struct in_addr *)malloc(sizeof(struct in_addr)); memcpy(inwk, &ip->ip_src, sizeof(struct in_addr)); ipaddr[i] = (struct in_addr *)inwk; printf("送信元IPアドレス:%15s\n", inet_ntoa(*(struct in_addr *) ipaddr[i])); udp_port[i] = udp->uh_dport; /*デバッグしたら中断したところ*/ printf("UDP送信先ポート番号:%15u\n", ntohs(udp_port[i])); if (i == 100) free(inwk); }

  • 文字列操作について(winsockの関数を用いています)

    こんばんは。 Winsockを用いてネットワークプログラミングを行っています。 A→Bへパケットを送信し、B側にてinet_ntoa関数(IPアドレスを文字列として表示させる関数)を用いて、以下のif文の条件を記述したのですが、if文内の条件がうまく動作しません。 デバッガを使用し、IPaddr内を見てみたところ、フフフフフフフフ……と言う文字列?が入っている状態です。 IPaddrに例えば、192.168.100.50等のIPアドレスを格納可能でしょうか? IPaddr[256] strcpy(IPaddr,inet_ntoa(from.sin_addr)); if(IPaddr == inet_ntoa(from.sin_addr)){  //別関数へ } よろしくお願い致します。

  • strcmpでIP比較

    お世話になります PHPのstrcmp()を使ってIPアドレスの比較をしているのですが、全く同じIPアドレスなのに0を返してくれません。 何故でしょうか? echo strcmp(999.99.999.999,999.99.999.999); -1が返ってきます。 宜しくお願いします。

    • ベストアンサー
    • PHP
  • IPアドレスを抽出して出力するプログラム

    下記のプログラムはIPアドレスを表示するプログラムです。for文を見てくれたら分かると思いますが、iが0~5まで繰り返し処理されるので、アドレスが5つ表示される結果になります。 このアドレスの先頭の数字(例えば「196.x.x.x」だと196)だけを見て先頭が196から始まるアドレスは表示して、先頭が196以外のアドレスは表示しないようにするにはどう書き加えればうまく実行できますか? OSはWinXPでコンパイラVC++です。 #include <stdio.h> #include <winsock2.h> #include <iphlpapi.h> int main() { DWORD i; PMIB_UDPTABLE pUdpTable; DWORD dwSize = 0; DWORD dwRetVal = 0; char *addr_ptr; if (GetUdpTable(NULL, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { pUdpTable = (MIB_UDPTABLE *) malloc (dwSize); } if ((dwRetVal = GetUdpTable(pUdpTable, &dwSize, 0)) == NO_ERROR) { if (pUdpTable->dwNumEntries > 0) { for (i=0; i<5; i++) { addr_ptr = (char *)&pUdpTable->table[i].dwLocalAddr; printf("Your Address: %s\n", inet_ntoa(*(struct in_addr *)addr_ptr)); } } } else { printf("GetUdpTable failed.\n"); LPVOID lpMsgBuf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //Default language (LPTSTR) &lpMsgBuf, 0, NULL )) { printf("\tError: %s", lpMsgBuf); } LocalFree( lpMsgBuf ); } return 0; }

  • 文字列の並び替えについて。

    #include<stdio.h> #include<string.h> main() {char name[40][50]; int i; for(i=1;i<=;i++){ printf("名前="); gets(name[i]); } if(strcmp(name[1],name[2])>0){ printf("%s %s \n",name[2],name[1]);} if(strcmp(name[1],name[2])<0){ printf("%s %s \n",name[1],name[2]);} if(strcmp(name[1],name[2])==0){ printf("%s %s \n",name[1]);} } は二人の名前を早い順に並べ替えるものなんですが、これを五人の名前を並べ替えるものにしたいので、どのようなプログラムにしたらいいのか教えてください。

  • C言語 strcmp 半角スペースがあるとだめ?

    C言語 strcmp 半角スペースが文字列に含まれている場合 文字列の比較がうまくいきません。半角スペースがあると比較できないのでしょうか? プログラム //strcmp #include <stdio.h> #include <string.h> int main(void){ char input[256]; char str[] = "HelloWorld!";   //char str[] = "Hello World!";だとうまくいかない。 printf("%s\n>", str); scanf("%s", input); if ( strcmp(input, str) == 0){ printf("同じです。\n"); }else{ printf("違います。\n"); } return 0; }

  • プログラムが動きません。

    プログラムが動きません。 ファイルuniqipにはIPアドレスが書き込まれています。そのファイルからIPアドレスを文字列ipに格納します。 ファイルtmp4には、85.114.143.2 34f4ff4acb18802170a939ae42dcd5ee0eeccda4 のようにIPアドレスとハッシュ値が書き込まれています。 tmp4に現れるIPアドレスで、uniqipに一致するものに対応するハッシュ値を printf("file%d,%s\n",i,hash); の形で出力しようと思いましたが、うまくいきません。 何がまずいのでしょうか? #include <stdio.h> #include <string.h> //ひとつのIPアドレスに現れるユニークなハッシュ値の数をカウントする int main() { FILE *fp,*gp; char ip[269730][16]; char ip2[16]; char hash[42]; int i,j; fp = fopen("uniqip","r"); if(fp == NULL){ printf("can not open the file.\n"); return 1; } for(i=0;i<267930;i++) { fscanf(fp,"%s",ip[i]); //printf("%s\n",ip[i]); } fclose(fp); ////////////////////////////////////////////////////////////////////////////////////////////////////// gp = fopen("tmp4","r"); if(gp == NULL){ printf("can not open the file.\n"); return 1; } for(i=0;i<267930;i++){ for(j=0;j<2470766;j++){ fscanf(gp,"%s %s",ip2,hash); printf("%s\n",ip[i]); if(!strcmp(ip[i],ip2)) { printf("file%d,%s\n",i,hash); } } } return 0; }

専門家に質問してみよう