diff --git a/src/ipxwrapper.def b/src/ipxwrapper.def index 14ec9c9..7d14aaf 100644 --- a/src/ipxwrapper.def +++ b/src/ipxwrapper.def @@ -15,3 +15,4 @@ EXPORTS WSARecvEx ioctlsocket WSHEnumProtocols + connect diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index b823ca8..05ef455 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -39,6 +39,7 @@ #define IPX_SEND (int)(1<<3) #define IPX_RECV (int)(1<<4) #define IPX_REUSE (int)(1<<6) +#define IPX_CONNECTED (int)(1<<7) #define RETURN(...) \ unlock_sockets();\ @@ -64,11 +65,8 @@ struct ipx_socket { struct sockaddr_ipx addr; uint32_t nic_bcast; - /* Extra bind address, only used for receiving packets. - * Only defined when IPX_EX_BOUND is set. - */ - struct ipx_interface *ex_nic; - uint16_t ex_socket; + /* Address used with connect call, only set when IPX_CONNECTED is */ + struct sockaddr_ipx remote_addr; ipx_socket *next; }; @@ -131,5 +129,6 @@ int WSAAPI r_setsockopt(SOCKET,int,int,const char*,int); int WSAAPI r_shutdown(SOCKET,int); SOCKET WSAAPI r_socket(int,int,int); int PASCAL r_ioctlsocket(SOCKET fd, long cmd, u_long *argp); +int PASCAL r_connect(SOCKET fd, const struct sockaddr *addr, int addrlen); #endif /* !IPXWRAPPER_H */ diff --git a/src/ipxwrapper_stubs.txt b/src/ipxwrapper_stubs.txt index 97e472d..8b726dc 100644 --- a/src/ipxwrapper_stubs.txt +++ b/src/ipxwrapper_stubs.txt @@ -31,3 +31,4 @@ r_setsockopt:4 r_shutdown:4 r_socket:4 r_ioctlsocket:4 +r_connect:4 diff --git a/src/router.c b/src/router.c index 36291c1..1460ad0 100644 --- a/src/router.c +++ b/src/router.c @@ -297,7 +297,10 @@ DWORD router_main(void *arg) { packet->dest_socket == ra->addr.sa_socket && /* Check source IP is within correct subnet */ - ((ra->ipaddr & ra->netmask) == (addr.sin_addr.s_addr & ra->netmask) || !global_conf.filter) + ((ra->ipaddr & ra->netmask) == (addr.sin_addr.s_addr & ra->netmask) || !global_conf.filter) && + + /* Check source address matches remote_addr if set */ + (ra->remote_addr.sa_family == AF_UNSPEC || (memcmp(ra->remote_addr.sa_netnum, packet->src_net, 4) == 0 && memcmp(ra->remote_addr.sa_nodenum, packet->src_node, 6) == 0)) ) { addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = ra->local_port; @@ -538,6 +541,18 @@ static int router_set_reuse(struct router_vars *router, SOCKET control, SOCKET s return 1; } +static BOOL router_set_remote(struct router_vars *router, SOCKET control, SOCKET sock, const struct sockaddr_ipx *addr) { + EnterCriticalSection(&(router->crit_sec)); + + struct router_addr *ra = router_get(router, control, sock); + if(ra) { + ra->remote_addr = *addr; + } + + LeaveCriticalSection(&(router->crit_sec)); + return TRUE; +} + static BOOL router_handle_call(struct router_vars *router, int sock, struct router_call *call) { struct router_ret ret; @@ -577,6 +592,11 @@ static BOOL router_handle_call(struct router_vars *router, int sock, struct rout break; } + case rc_remote: { + router_set_remote(router, sock, call->sock, &(call->arg_addr)); + break; + } + default: { log_printf("Recieved unknown call, dropping client"); return FALSE; @@ -893,3 +913,27 @@ BOOL rclient_set_reuse(struct rclient *rclient, SOCKET sock, BOOL reuse) { WSASetLastError(WSAENETDOWN); return FALSE; } + +BOOL rclient_set_remote(struct rclient *rclient, SOCKET sock, const struct sockaddr_ipx *addr) { + if(rclient->sock != -1) { + struct router_call call; + struct router_ret ret; + + call.call = rc_remote; + call.sock = sock; + call.arg_addr = *addr; + + if(!rclient_do(rclient, &call, &ret)) { + return FALSE; + } + + return TRUE; + }else if(rclient->router) { + return router_set_remote(rclient->router, 0, sock, addr); + } + + log_printf("rclient_bind: No router?!"); + + WSASetLastError(WSAENETDOWN); + return FALSE; +} diff --git a/src/router.h b/src/router.h index c18a67a..23ce35e 100644 --- a/src/router.h +++ b/src/router.h @@ -31,7 +31,8 @@ struct router_call { rc_unbind, rc_port, rc_filter, - rc_reuse + rc_reuse, + rc_remote } call; SOCKET sock; @@ -61,6 +62,9 @@ struct router_addr { uint32_t ipaddr; uint32_t netmask; + /* Only accept packets from this address (any if AF_UNSPEC) */ + struct sockaddr_ipx remote_addr; + struct router_addr *next; }; @@ -114,5 +118,6 @@ 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_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 c737d9a..92b60d7 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -741,3 +741,64 @@ int PASCAL ioctlsocket(SOCKET fd, long cmd, u_long *argp) { return r_ioctlsocket(fd, cmd, argp); } + +int PASCAL connect(SOCKET fd, const struct sockaddr *addr, int addrlen) { + ipx_socket *sockptr = get_socket(fd); + + if(sockptr) { + if(addrlen < sizeof(struct sockaddr_ipx)) { + RETURN_WSA(WSAEFAULT, -1); + } + + struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr; + + const unsigned char z6[] = {0,0,0,0,0,0}; + + if(ipxaddr->sa_family == AF_UNSPEC || (ipxaddr->sa_family == AF_IPX && memcmp(ipxaddr->sa_nodenum, z6, 6) == 0)) { + if(!(sockptr->flags & IPX_CONNECTED)) { + RETURN(0); + } + + struct sockaddr_ipx dc_addr; + dc_addr.sa_family = AF_UNSPEC; + + if(!rclient_set_remote(&g_rclient, fd, &dc_addr)) { + RETURN(-1); + } + + sockptr->flags &= ~IPX_CONNECTED; + + RETURN(0); + } + + if(ipxaddr->sa_family != AF_IPX) { + RETURN_WSA(WSAEAFNOSUPPORT, -1); + } + + if(!(sockptr->flags & IPX_BOUND)) { + log_printf("connect() on unbound socket, attempting implicit bind"); + + struct sockaddr_ipx bind_addr; + + bind_addr.sa_family = AF_IPX; + memcpy(bind_addr.sa_netnum, ipxaddr->sa_netnum, 4); + memset(bind_addr.sa_nodenum, 0, 6); + bind_addr.sa_socket = 0; + + if(bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) { + RETURN(-1); + } + } + + if(!rclient_set_remote(&g_rclient, fd, ipxaddr)) { + RETURN(-1); + } + + memcpy(&(sockptr->remote_addr), addr, sizeof(*ipxaddr)); + sockptr->flags |= IPX_CONNECTED; + + RETURN(0); + }else{ + return r_connect(fd, addr, addrlen); + } +} diff --git a/src/wsock32_stubs.txt b/src/wsock32_stubs.txt index f353af9..0c463c3 100644 --- a/src/wsock32_stubs.txt +++ b/src/wsock32_stubs.txt @@ -1,7 +1,7 @@ accept bind:0 closesocket:0 -connect +connect:0 getpeername getsockname:0 getsockopt:0