diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 98bb4265892..7ad118f3452 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -178,6 +178,8 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); struct interface_filter { struct sock_filter iface_memaddr; struct sock_filter iface_rule; + struct sock_filter ip_memaddr; + struct sock_filter ip_rule; struct sock_filter return_keep; struct sock_filter return_dump; }; @@ -187,9 +189,17 @@ struct interface_filter { # define FILTER_JUMP_KEEP(here) (u_char)(offsetof(struct interface_filter, return_keep) \ -offsetof(struct interface_filter, here)-sizeof(struct sock_filter)) \ /sizeof(struct sock_filter) +# define FILTER_JUMP_NEXT() (u_char)(0) +# define SKF_NET_DESTIP 16 /* offset in the network header to the destination IP */ static struct interface_filter generic_interface_filter = { + /* This filter rule allows incoming packets on the specified interface, which works for all + * remotely generated packets and for locally generated broadcast packets. */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, SKF_AD_OFF+SKF_AD_IFINDEX), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xdeadbeef, FILTER_JUMP_KEEP(iface_rule), FILTER_JUMP_DUMP(iface_rule)), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xdeadbeef, FILTER_JUMP_KEEP(iface_rule), FILTER_JUMP_NEXT()), + /* This rule allows locally generated packets targeted at the specific IP address of the chosen + * adapter (local packets not destined for the broadcast address do not have IFINDEX set) */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, SKF_NET_OFF+SKF_NET_DESTIP), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xdeadbeef, FILTER_JUMP_KEEP(ip_rule), FILTER_JUMP_DUMP(ip_rule)), BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* keep packet */ BPF_STMT(BPF_RET+BPF_K, 0) /* dump packet */ }; @@ -2191,6 +2201,7 @@ static BOOL interface_bind( SOCKET s, int fd, struct sockaddr *addr ) goto cleanup; /* Failed to suggest egress interface */ specific_interface_filter = generic_interface_filter; specific_interface_filter.iface_rule.k = adapter->Index; + specific_interface_filter.ip_rule.k = htonl(adapter_addr); filter_prog.len = sizeof(generic_interface_filter)/sizeof(struct sock_filter); filter_prog.filter = (struct sock_filter *) &specific_interface_filter; if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) != 0)