ws2_32: Fix interface-bound filter to accept locally generated targeted packets.

This commit is contained in:
Erich Hoover 2013-06-23 20:19:16 -06:00 committed by Alexandre Julliard
parent c66d94bfd9
commit 74010aa0e7
1 changed files with 12 additions and 1 deletions

View File

@ -178,6 +178,8 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
struct interface_filter { struct interface_filter {
struct sock_filter iface_memaddr; struct sock_filter iface_memaddr;
struct sock_filter iface_rule; struct sock_filter iface_rule;
struct sock_filter ip_memaddr;
struct sock_filter ip_rule;
struct sock_filter return_keep; struct sock_filter return_keep;
struct sock_filter return_dump; 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) \ # define FILTER_JUMP_KEEP(here) (u_char)(offsetof(struct interface_filter, return_keep) \
-offsetof(struct interface_filter, here)-sizeof(struct sock_filter)) \ -offsetof(struct interface_filter, here)-sizeof(struct sock_filter)) \
/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 = { 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_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, (u_int)-1), /* keep packet */
BPF_STMT(BPF_RET+BPF_K, 0) /* dump 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 */ goto cleanup; /* Failed to suggest egress interface */
specific_interface_filter = generic_interface_filter; specific_interface_filter = generic_interface_filter;
specific_interface_filter.iface_rule.k = adapter->Index; 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.len = sizeof(generic_interface_filter)/sizeof(struct sock_filter);
filter_prog.filter = (struct sock_filter *) &specific_interface_filter; filter_prog.filter = (struct sock_filter *) &specific_interface_filter;
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) != 0) if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) != 0)