2017-11-25 23 views
5

私は2つのアプリケーションからポートを使用しようとしており、それぞれが異なるIPアドレスのセットからパケットを受信するようにしています。これを達成するために、私はSO_REUSEPORTとSO_ATTACH_REUSEPORT_CBPFソケットオプションを使用します。次のように私のコードは次のとおりです。SO_ATTACH_REUSEPORT_CBPFソケットオプションの予期しない動作

parentfd = socket(AF_INET, SOCK_STREAM, 0); 
if (parentfd < 0) 
    error("ERROR opening socket"); 

struct sock_filter code[]={ 
    { 0x28, 0, 0, 0x0000000c }, 
    { 0x15, 0, 3, 0x00000800 }, 
    { 0x20, 0, 0, 0x0000001a }, 
    { 0x15, 2, 0, 0xc0a8ff01 }, 
    { 0x6, 0, 0, 0x00000000 }, 
    { 0x6, 0, 0, 0x00040000 }, 
    { 0x6, 0, 0, 0x00000001 }, 
}; 

struct sock_fprog bpf = { 
    .len = ARRAY_SIZE(code), 
    .filter = code, 
}; 

if (setsockopt(parentfd, SOL_SOCKET, SO_REUSEPORT, (const void *)&optval,sizeof(optval))) 
    error("ERROR setting SO_REUSEPORT"); 

if (setsockopt(parentfd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, (const void *)&bpf, sizeof(bpf))) 
    error("ERROR setting SO_ATTACH_REUSEPORT_CBPF); 

私ものみ SO_REUSEPORTフラグを使用して、同じポートをリスニング異なるプロセスを持っています。 IP 192.168.255.1のマシンからecho 1234 | ncat 192.168.255.150 1234を実行しています。私のフィルタに基づいて、私はそのIPアドレスからのすべてのトラフィックが第2のプロセスによって受信されると期待します。しかし、それは最初にすべて受信されます。私はシンプルにフィルタを変更した場合:

struct sock_filter code[]={ { 0x6, 0, 0, 0x00000001 }, };

を期待し、すべてのパケットが第二のプロセスによって受信されるように、それは動作します。なぜこれが起こっているかもしれないのか?

+1

を返すことです? –

答えて

1

問題の原因を突き止めました。このフィルタは、TCPハンドシェイクパケットでさえ、すべてのパケットに適用されます。また、基本ポインタは、ヘッダーではなく、パケットペイロードの最初のバイトを指します。したがって、ときに実行さ

ldh[12] 

それは、パケットの制限(SYNパケットは、ペイロードの0バイトを持っている)の外に取得し、デフォルトの動作を使用すると、元のフィルタを思い付いた方法0

0

非稼働コードは次のとおりです。

l0: ldh [12]     /* read EtherType (2 bytes), which is found at offset 12 (decimal) */ 
l1: jeq #0x800, l2, l5   /* if EtherType == `0x800` (IPv4), jump to `l2`, otherwise jump to `l5` */ 
l2: ld [26]     /* read source IP address (4 bytes) */ 
l3: jeq #0xc0a8ff01, l6, l4 /* if source IP address == 192.168.255.1, jump to l6 (return 1), else jump to l4 (return 0) */ 
l4: ret #0 
l5: ret #0x40000 
l6: ret #0x1 

作業コードは次のとおりです。

ret #0x1 

socket (7)は言う:

BPFプログラムは、0とNの間にインデックスを返す必要があります-1はパケットを受け取るべきソケットを表します(Nはグループ内のソケットの数です)。 BPFプログラムが無効なインデックスを返した場合、ソケットの選択は通常のSO_REUSEPORTメカニズムに戻ります。私のマシン上で

tcpdump -i lo -ddd 'src host 192.168.255.1'は、私はあなたのコードでは明らかに間違っているものを見ることができない

l0: ldh [12] 
l1: jeq #0x800, l2, l4 
l2: ld [26] 
l3: jeq #0xc0a8ff01, l8, l9 
l4: jeq #0x806, l6, l5 
l5: jeq #0x8035, l6, l9 
l6: ld [28] 
l7: jeq #0xc0a8ff01, l8, l9 
l8: ret #0x40000 
l9: ret #0 

ある

10 
40 0 0 12 
21 0 2 2048 
32 0 0 26 
21 4 5 3232300801 
21 1 0 2054 
21 0 3 32821 
32 0 0 28 
21 0 1 3232300801 
6 0 0 262144 
6 0 0 0 

を生成します。

サーバでtcpdumpを実行しようとしましたか?クライアントで余分なIPアドレスを削除することを忘れてしまったのでしょうか、またはどこかで忘れられたSNATルールがありますか?

実行しているカーネルバージョンはどれですか?問題を再現する最小限のCアプリケーションを投稿できますか?