From fd555ce7c22a2ad9323dec6323a4f240a1df12d4 Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Sat, 17 Sep 2011 23:47:31 +0000 Subject: [PATCH] Implemented IPX_RECEIVE_BROADCAST option, updated router/rclient API and added proper checks when receiving broadcast packets to the router main loop. --- Makefile | 2 +- src/ipxwrapper.h | 1 + src/router.c | 60 ++++++++++++++++++++++++++---------------------- src/router.h | 8 +++---- src/winsock.c | 43 ++++++++++++++++++++-------------- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 55e69fb..5554f6a 100644 --- a/Makefile +++ b/Makefile @@ -85,5 +85,5 @@ src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt src/%_stubs.o: src/%_stubs.s nasm -f win32 -o $@ $< -src/%.o: src/%.c src/ipxwrapper.h src/config.h src/common.h +src/%.o: src/%.c src/ipxwrapper.h src/config.h src/common.h src/router.h $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index 7519f16..3a01f76 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -38,6 +38,7 @@ #define IPX_RECV (int)(1<<4) #define IPX_REUSE (int)(1<<6) #define IPX_CONNECTED (int)(1<<7) +#define IPX_RECV_BCAST (int)(1<<8) #define RETURN(...) \ unlock_sockets();\ diff --git a/src/router.c b/src/router.c index 9131688..f8c5124 100644 --- a/src/router.c +++ b/src/router.c @@ -287,8 +287,8 @@ DWORD router_main(void *arg) { if( ra->local_port && (ra->filter_ptype < 0 || ra->filter_ptype == packet->ptype) && - (memcmp(packet->dest_net, ra->addr.sa_netnum, 4) == 0 || memcmp(packet->dest_net, f6, 4) == 0) && - (memcmp(packet->dest_node, ra->addr.sa_nodenum, 6) == 0 || memcmp(packet->dest_node, f6, 6) == 0) && + (memcmp(packet->dest_net, ra->addr.sa_netnum, 4) == 0 || (memcmp(packet->dest_net, f6, 4) == 0 && (ra->flags & IPX_BROADCAST || !global_conf.w95_bug) && ra->flags & IPX_RECV_BCAST)) && + (memcmp(packet->dest_node, ra->addr.sa_nodenum, 6) == 0 || (memcmp(packet->dest_node, f6, 6) == 0 && (ra->flags & IPX_BROADCAST || !global_conf.w95_bug) && ra->flags & IPX_RECV_BCAST)) && packet->dest_socket == ra->addr.sa_socket && /* Check source IP is within correct subnet */ @@ -314,7 +314,7 @@ DWORD router_main(void *arg) { return 0; } -static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse) { +static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, int flags) { /* Network number 00:00:00:00 is specified as the "current" network, this code * treats it as a wildcard when used for the network OR node numbers. * @@ -406,7 +406,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct router_addr *a = router->addrs; while(a) { - if(a->addr.sa_socket == addr->sa_socket && (!a->reuse || !reuse)) { + if(a->addr.sa_socket == addr->sa_socket && (!(a->flags & IPX_REUSE) || !(flags & IPX_REUSE))) { log_printf("bind failed: requested socket in use"); LeaveCriticalSection(&(router->crit_sec)); @@ -433,7 +433,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, new_addr->ws_socket = sock; new_addr->control_socket = control; new_addr->filter_ptype = -1; - new_addr->reuse = reuse; + new_addr->flags = flags; new_addr->ipaddr = iface_ipaddr; new_addr->netmask = iface_netmask; new_addr->next = router->addrs; @@ -512,28 +512,30 @@ static void router_set_filter(struct router_vars *router, SOCKET control, SOCKET LeaveCriticalSection(&(router->crit_sec)); } -static int router_set_reuse(struct router_vars *router, SOCKET control, SOCKET sock, BOOL reuse) { +static int router_set_flags(struct router_vars *router, SOCKET control, SOCKET sock, int flags) { EnterCriticalSection(&(router->crit_sec)); struct router_addr *addr = router_get(router, control, sock); if(addr) { - struct router_addr *test = router->addrs; - - while(test) { - if(addr != test && memcmp(&(addr->addr), &(test->addr), sizeof(struct sockaddr_ipx)) == 0 && !reuse) { - /* Refuse to disable SO_REUSEADDR when another binding for the same address exists */ - LeaveCriticalSection(&(router->crit_sec)); - return 0; - } + if(addr->flags & IPX_REUSE && !(flags & IPX_REUSE)) { + struct router_addr *test = router->addrs; - test = test->next; + while(test) { + if(addr != test && memcmp(&(addr->addr), &(test->addr), sizeof(struct sockaddr_ipx)) == 0) { + /* Refuse to disable SO_REUSEADDR when another binding for the same address exists */ + LeaveCriticalSection(&(router->crit_sec)); + return WSAEINVAL; + } + + test = test->next; + } } - addr->reuse = reuse; + addr->flags = flags; } LeaveCriticalSection(&(router->crit_sec)); - return 1; + return ERROR_SUCCESS; } static BOOL router_set_remote(struct router_vars *router, SOCKET control, SOCKET sock, const struct sockaddr_ipx *addr) { @@ -579,11 +581,8 @@ static BOOL router_handle_call(struct router_vars *router, int sock, struct rout break; } - case rc_reuse: { - if(!router_set_reuse(router, sock, call->sock, call->arg_int)) { - ret.err_code = WSAEINVAL; - } - + case rc_flags: { + ret.err_code = router_set_flags(router, sock, call->sock, call->arg_int); break; } @@ -879,14 +878,14 @@ BOOL rclient_set_filter(struct rclient *rclient, SOCKET sock, int ptype) { return FALSE; } -BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) { +BOOL rclient_set_flags(struct rclient *rclient, SOCKET sock, int flags) { if(rclient->sock != -1) { struct router_call call; struct router_ret ret; - call.call = rc_reuse; + call.call = rc_flags; call.sock = sock; - call.arg_int = reuse; + call.arg_int = flags; if(!rclient_do(rclient, &call, &ret)) { return FALSE; @@ -895,11 +894,18 @@ BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) { if(ret.err_code == ERROR_SUCCESS) { return TRUE; }else{ - WSASetLastError(WSAEINVAL); + WSASetLastError(ret.err_code); return FALSE; } }else if(rclient->router) { - router_set_reuse(rclient->router, 0, sock, reuse); + int err = router_set_flags(rclient->router, 0, sock, flags); + if(err == ERROR_SUCCESS) { + return TRUE; + }else{ + WSASetLastError(err); + return FALSE; + } + return TRUE; } diff --git a/src/router.h b/src/router.h index ced160c..8d0a9ab 100644 --- a/src/router.h +++ b/src/router.h @@ -31,7 +31,7 @@ struct router_call { rc_unbind, rc_port, rc_filter, - rc_reuse, + rc_flags, rc_remote } call; @@ -56,7 +56,7 @@ struct router_addr { SOCKET ws_socket; /* Application socket */ SOCKET control_socket; /* Control socket */ int filter_ptype; /* Packet type filter, negative to disable */ - BOOL reuse; /* SO_REUSEADDR */ + int flags; /* Address of IP interface */ uint32_t ipaddr; @@ -118,11 +118,11 @@ BOOL rclient_init(struct rclient *rclient); BOOL rclient_start(struct rclient *rclient); void rclient_stop(struct rclient *rclient); -BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, BOOL reuse); +BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast, int flags); BOOL rclient_unbind(struct rclient *rclient, SOCKET sock); BOOL rclient_set_port(struct rclient *rclient, SOCKET sock, uint16_t port); BOOL rclient_set_filter(struct rclient *rclient, SOCKET sock, int ptype); -BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse); +BOOL rclient_set_flags(struct rclient *rclient, SOCKET sock, int flags); BOOL rclient_set_remote(struct rclient *rclient, SOCKET sock, const struct sockaddr_ipx *addr); #endif /* !IPXWRAPPER_ROUTER_H */ diff --git a/src/winsock.c b/src/winsock.c index 5ba8358..07f1f9e 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -160,7 +160,7 @@ SOCKET WSAAPI socket(int af, int type, int protocol) { return -1; } - nsock->flags = IPX_SEND | IPX_RECV; + nsock->flags = IPX_SEND | IPX_RECV | IPX_RECV_BCAST; nsock->s_ptype = (protocol ? NSPROTO_IPX - protocol : 0); lock_sockets(); @@ -544,6 +544,18 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F return r_getsockopt(fd, level, optname, optval, optlen); } +#define SET_FLAG(flag, state) \ + if(state) { \ + sockptr->flags |= flag; \ + }else{ \ + sockptr->flags &= flag; \ + } + +#define RC_SET_FLAG(flag, state) \ + if(sockptr->flags & IPX_BOUND && !rclient_set_flags(&g_rclient, fd, (sockptr->flags & ~(flag)) | ((state) ? (flag) : 0))) { \ + RETURN(-1); \ + } + int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, int optlen) { int *intval = (int*)optval; BOOL *bval = (BOOL*)optval; @@ -578,28 +590,25 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, RETURN(0); } + if(optname == IPX_RECEIVE_BROADCAST) { + RC_SET_FLAG(IPX_RECV_BCAST, *bval); + SET_FLAG(IPX_RECV_BCAST, *bval); + + RETURN(0); + } + RETURN_WSA(WSAENOPROTOOPT, -1); } if(level == SOL_SOCKET) { if(optname == SO_BROADCAST) { - if(*bval) { - sockptr->flags |= IPX_BROADCAST; - }else{ - sockptr->flags &= ~IPX_BROADCAST; - } - + SET_FLAG(IPX_BROADCAST, *bval); RETURN(0); - }else if(optname == SO_REUSEADDR) { - if(sockptr->flags & IPX_BOUND && !rclient_set_reuse(&g_rclient, fd, *bval)) { - RETURN(-1); - } - - if(*bval) { - sockptr->flags |= IPX_REUSE; - }else{ - sockptr->flags &= ~IPX_REUSE; - } + } + + if(optname == SO_REUSEADDR) { + RC_SET_FLAG(IPX_REUSE, *bval); + SET_FLAG(IPX_REUSE, *bval); RETURN(0); }