0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ipfilter 実装

Last updated at Posted at 2020-06-15

0. 概要

BSD系では、ioctl()のコールによりipfilter(ipfコマンド)の機能が実装できる。
カーネルバージョンによって実装が異なるので注意。

  1. フィルタを有効/無効する:SIOCFRENB
  2. フィルタをFLUSHする:SIOCIPFFL
  3. フィルタを追加/削除する:SIOCADAFR
  4. キーワード

1. フィルタを有効にする:SIOCFRENB

SIOCFRENBで有効(ipf -E)/無効(ipf -D)の実装ができる。
先に有効にしないと、以降のフィルタ操作はEIO(5):Input/output errorとなる。

unsigned int enable = 1; /* 0で無効 */
int ipf_fd = open(IPL_NAME, O_RDWR);
ioctl(ipf_fd, SIOCFRENB, &enable);

2. フィルタをFLUSHする:SIOCIPFFL

SIOCIPFFLフィルタを削除(ipf -F)できる

int fl = 0; /* 0で全削除。1で確立していないものを削除 */
fl = FR_OUTQUE|FR_INQUE; /* ipf -Fa */
ioctl(ipf_fd, SIOCIPFFL, &fl);

3. フィルタを追加/削除する:SIOCADAFR/SIOCRMAFR

SIOCADAFRで追加、SIOCRMAFRで削除ができる。
以下に設定例を記述する。
ipf.confの以下に該当するフィルタである。

pass in quick from 192.168.11.0/24 to any port=22
pass in quick from any to any port 80:443
block in quick from any to any port all

ipfobj_t obj;  /* obj.ipfo_ptr = &fre*/
frentry_t fre; /* fre.fr_ipf = &ipft*/
fripf_t ipft;

/* ipfilter */
obj.ipfo_rev = IPFILTER_VERSION;
obj.ipfo_size = sizeof(fre);
obj.ipfo_type = IPFOBJ_FRENTRY;
obj.ipfo_ptr = &fre;

memset(&obj, 0x00, sizeof(obj));
fre.fr_ipf = &ipft; /* 以降で参照されるので、先にセットした方が良い。 */
fre.fr_isc = (struct ipscan *)-1;
fre.fr_loglevel = 0xffff;
fre.fr_type = FR_T_IPF;
fre.fr_dsize = sizeof(fripf_t);

/* 適用するI/Fを限定したい場合 */
/* ipf.conf: on eth0 */
strncpy(fre.fr_ifname, "eth0", LIFNAMSIZ - 1);

/* フィルタ設定 */
memset(&ipft, 0, sizeof(ipft));
/* freを参照しているつもりでもfre.fr_ipfを参照する場合がある。 */
/* fre.fr_ipfがNULLだとSegmentation Faultとなるので注意。 */
fre.fr_sifpidx = -1; /* #define fr_sifpidx fr_ipf->fri_sifpidx */
fre.fr_difpidx = -1; /* #define fr_difpidx fr_ipf->fr_difpidx */

/* フィルタ設定 */
/* 受信:192.168.11.0/24からのSSHのみ受け入れ */
/* ipf.conf: pass in quick */
/* FR_QUICKで最初の一致。*/
/* FR_KEEPSTATEで反対方向の許可(受信に対する応答送信の許可)。 */
fre.fr_flags = FR_PASS | FR_INQUE | FR_QUICK | FR_KEEPSTATE;
fre.fr_v = 4; /* IPv4指定。IPv6の場合は6。 */
fre.fr_ip.fi_v = fre.fr_v;
fre.fr_mip.fi_v = 0xf;

/* IPアドレス範囲。受信パケットのSrcアドレスを指定する。 */
/* ipf.conf: from 192.168.11.0/24  */
inet_pton(AF_INET, "192.168.11.0", &fre.fr_src);
inet_pton(AF_INET, "255.255.255.0", &fre.fr_smsk);

/* ポート。受信パケット中のDstポートを指定する。 */
fre.fr_proto = IPPROTO_TCP;
fre.fr_dcmp  = FR_EQUAL;
fre.fr_dport = 22;

ioctl(ipf_fd, SIOCADAFR, &obj); /* 削除はSIOCRMAFR */

/* 送信:特定のポートのみ可 */
fre.fr_flags = FR_PASS | FR_OUTQUE | FR_QUICK;

/* フィルタ構造体を使いまわす場合はクリアを忘れずに */
memset(&fre.fr_src, 0, sizeof(fre.fr_src));
memset(&fre.fr_smsk, 0, sizeof(fre.fr_smsk));

fre.fr_proto = 0;
fre.fr_dcmp  = 0;
fre.fr_dport = 0;

/* IPアドレス範囲。全ての送信先。 */
/* ipf.conf: to any  */
memset(&fre.fr_dst, 0, sizeof(fre.fr_dst));
memset(&fre.fr_dmsk, 0, sizeof(fre.fr_dmsk));

/* ポート。TCP 80から443への送信可。送信パケット中のDstポートを指定する。 */
/* ipf.conf: port 80:443 */
fre.fr_proto = IPPROTO_TCP;
fre.fr_dcmp  = FR_INCRANGE;
fre.fr_dport = 80;
fre.fr_dtop  = 443;

ioctl(ipf_fd, SIOCADAFR, &obj); /* 削除はSIOCRMAFR */

/* 上記以外の送受信すべてブロック */	
memset(&ipft, 0, sizeof(ipft));
fre.fr_flags = FR_BLOCK | FR_INQUE | FR_QUICK;
ioctl(ipf_fd, SIOCADAFR, &obj);

fre.fr_flags = FR_BLOCK | FR_OUTQUE| FR_QUICK;
ioctl(ipf_fd, SIOCADAFR, &obj);

4. キーワード

 ipf(4) : netinet/ip_fil.hの内容が記載。ioctlの定義や関連定義が記載されている。
 ipf(5) : ipf.confの記述法について。
 man ipf : ipfコマンドについて。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?