プロが教える店舗&オフィスのセキュリティ対策術

パケットモニタリング(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です。

A 回答 (6件)

がると申します。


んっと…ちょっと長くなりますのであらかじめお詫びを。

取り合えず上から順番に。

int *pa[2048];
確保したいものが「struct in_addr *」であるからには(ip->ip_src の構造体の中身をチェック!!)、これは
struct in_addr *pa[10];
としたほうがよいでしょう。かつ、今回の例ですと「関数を抜けた後もデータを保持したい」っぽいので、正確には
static struct in_addr *pa[10];
と記述されるべきです。

static int i = 1;
直後にインクリメントが入るので、このままですと「配列の添え字が2からスタート」になってしまいます。
ここはやはり
static int i = -1;
としておくのがよろしいかと。

struct in_addr *inwk;
後ほど使いますのでここで宣言しておきます。

pa[i] = (int *)&(ip->ip_src);
まず、キャストで「ポインタを無理やりintとして取得」するよりは、ストレートに「struct in_addr *」として保持したほうがよいです。
また、このままですと参照先が書き換わればデータも書き換わってしまうので(これが「全部addres[10]に代入されているIPアドレスが表示されてしま」う原因です)、ここは別途メモリを確保してデータを固定のものとして保持しておくべきでしょう。
したがって、このようなロジックに置換します(malloc後のfreeをしていないのでご注意を)。

// メモリ領域を新規に確保します
inwk = (struct in_addr *)malloc(sizeof(struct in_addr));

// データをコピーします
memcpy(inwk, &ip->ip_src, sizeof(struct in_addr));

// データを設定します
pa[i] = (struct in_addr *)inwk;


if (i == 10) {
添え字が10である場合、個数は11個になってしまいます。なので、10個で表示をしたいようであれば、ここは
if (i == 9) {
としておくとよいでしょう。

ほぼ同様の理由で
for (i = 1; i < 10; i++) {

for (i = 0; i < 10; i++) {
にします。

ーー
これで概ね問題なく動くかと思います。
全体の関数を記述しておきます。


void print_ip(struct ip *ip)
{
static struct in_addr *pa[16];
static int i = -1;

struct in_addr *inwk;

printf("| Source IP Address: %15s|\n", inet_ntoa(*(struct in_addr *) &(ip->ip_src)));

i++;

inwk = (struct in_addr *)malloc(sizeof(struct in_addr));
memcpy(inwk, &ip->ip_src, sizeof(struct in_addr));
pa[i] = (struct in_addr *)inwk;
printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i]));

if (i == 9) {
for (i = 0; i < 10; i++) {
printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i]));
}
}
}

まだまだ問題点は山積みですが、取り合えず意図する程度の動きはするのではないかと思いますが、どうでしょうか?
    • good
    • 0
この回答へのお礼

回答ありがとうございます。こちらの意図するようにプログラムが動いてくれました。貴重な時間、感謝いたします。ありがとうございました!

お礼日時:2006/01/06 21:10

paがstaticになってません。

これじゃデーターをためられない。

#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>

void
print_ip(struct ip *ip)
{
static struct in_addr pa[11];
static int i = 0;

i++;
pa[i] = ip->ip_src;
printf("送信先[%2d]%15s\n", i, inet_ntoa(pa[i]));

if (i == 10) {
printf("\n");
for (i = 1; i <= 10; i++) {
printf("送信先[%2d]%15s\n", i, inet_ntoa(pa[i]));
}
}
}

int
main(void)
{
int i;
char buf[16];
struct ip ip;

for (i = 0; i < 10; i++) {
sprintf(buf, "192.168.0.%d", i + 1);
inet_aton(buf, &ip.ip_src);
print_ip(&ip);
}
return 0;
}
    • good
    • 0
この回答へのお礼

おっしゃられた通り、paがstaticになっていませんでした。ご指摘ありがとうございました。上記のプログラムを参考に勉強していこうと思います。ありがとうございました。

お礼日時:2006/01/06 21:12

よく見たら、struct in_addr型でpaは配列宣言しないと駄目でしょう。



inet_ntoaに渡すのは、struct in_addr構造体のip_srcメンバです。実体を入れるので、pa[*].ip_srcでアクセスするように修正すれば上手く行くのでは?

この回答への補足

こちらの知識不足で申し訳ありません。
おっしゃられていることはこういった感じでよろしいでしょうか??

void print_ip(struct ip *ip)
{



struct in_addr pa[2048];

static int i = 0;



printf("Protocol: IP\n");
printf("+-----+------+------------+-------------------------+\n");
printf("| IV:%1u| HL:%2u| T: %8s| Total Length: %10u|\n",
ip->ip_v, ip->ip_hl, ip_ttoa(ip->ip_tos), ntohs(ip->ip_len));
printf("+-----+------+------------+-------+-----------------+\n");
printf("| Identifier: %5u| FF:%3s| FO: %5u|\n",
ntohs(ip->ip_id), ip_ftoa(ntohs(ip->ip_off)),
ntohs(ip->ip_off) &IP_OFFMASK);
printf("+------------+------------+-------+-----------------+\n");
printf("| TTL: %3u| Pro: %3u| Header Checksum: %5u|\n",
ip->ip_ttl, ip->ip_p, ntohs(ip->ip_sum));
printf("+------------+------------+-------------------------+\n");
printf("| Source IP Address: %15s|\n",
inet_ntoa(*(struct in_addr *) &(ip->ip_src)));
printf("+---------------------------------------------------+\n");
printf("| Destination IP Address: %15s|\n",
inet_ntoa(*(struct in_addr *) &(ip->ip_dst)));
printf("+---------------------------------------------------+\n");


i++;

pa[i] = ip->ip_src;
printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i].ip_src));
}

補足日時:2006/01/06 20:55
    • good
    • 0
この回答へのお礼

貴重な時間をお使いいただいてありがとうございました。
やはりまだまだ勉強不足を痛感しました。プログラムも思うように動いてくれました。本当に何回も回答していただいてありがとうございました。

お礼日時:2006/01/06 21:08

代入式の方も変更が必要です。



>pa[i] = (int *)&(ip->ip_src);
>&(ip->ip_src);

では、アドレス入れてます。

pa[i] = ip->ip_src;

では?

この回答への補足

たびたび申し訳ありません。ご指摘の部分を変えたら代入 に互換性のない型とでてしまいました。

補足日時:2006/01/06 19:32
    • good
    • 0

外の、変数iのループであるfor文か、while文がないように思いますが、


print_ip関数の全文を提示していただくわけには行かないですか?

この回答への補足

print_ip関数はこれで全文なのですが…
print_ip関数以外でループ処理をおこなってるみたいなんですが、全文だと800行ぐらいなんですが大丈夫でしょうか?


void print_ip(struct ip *ip)
{



int *pa[2048];

static int i = 0;



printf("Protocol: IP\n");
printf("+-----+------+------------+-------------------------+\n");
printf("| IV:%1u| HL:%2u| T: %8s| Total Length: %10u|\n",
ip->ip_v, ip->ip_hl, ip_ttoa(ip->ip_tos), ntohs(ip->ip_len));
printf("+-----+------+------------+-------+-----------------+\n");
printf("| Identifier: %5u| FF:%3s| FO: %5u|\n",
ntohs(ip->ip_id), ip_ftoa(ntohs(ip->ip_off)),
ntohs(ip->ip_off) &IP_OFFMASK);
printf("+------------+------------+-------+-----------------+\n");
printf("| TTL: %3u| Pro: %3u| Header Checksum: %5u|\n",
ip->ip_ttl, ip->ip_p, ntohs(ip->ip_sum));
printf("+------------+------------+-------------------------+\n");
printf("| Source IP Address: %15s|\n",
inet_ntoa(*(struct in_addr *) &(ip->ip_src)));
printf("+---------------------------------------------------+\n");
printf("| Destination IP Address: %15s|\n",
inet_ntoa(*(struct in_addr *) &(ip->ip_dst)));
printf("+---------------------------------------------------+\n");


i++;
if (i == 10) {
for (i = 1; i < 10; i++) {
printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) &(pa[i])));
}}
pa[i] = (int *) &(ip->ip_src);
printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) &(pa[i])));

}

補足日時:2006/01/06 19:31
    • good
    • 0

>int *pa[2048];



って宣言は、paのポインタを格納する配列を2048個作ってるのでは?

宣言を
int pa[2048];
にしてみては如何でしょうか?

この回答への補足

早速のアドバイスありがとうございます。
ご指摘の部分をint pa[2048];
に変えて見たところ、「代入により、キャストなしでポインタから整数を作りました」と警告が出てしまいました。
勉強不足で申し訳ありません。

補足日時:2006/01/06 17:58
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!