diff --git a/src/interface.c b/src/interface.c index 7057234..1843f58 100644 --- a/src/interface.c +++ b/src/interface.c @@ -220,6 +220,11 @@ ipx_interface_t *copy_ipx_interface(const ipx_interface_t *src) /* Free an ipx_interface structure and any memory allocated within. */ void free_ipx_interface(ipx_interface_t *iface) { + if(iface == NULL) + { + return; + } + ipx_interface_ip_t *a, *a_tmp; DL_FOREACH_SAFE(iface->ipaddr, a, a_tmp) diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index ac9de0a..962c440 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -63,7 +63,6 @@ struct ipx_socket { /* The following values are undefined when IPX_BOUND is not set */ struct sockaddr_ipx addr; - uint32_t nic_bcast; /* Address used with connect call, only set when IPX_CONNECTED is */ struct sockaddr_ipx remote_addr; diff --git a/src/router.c b/src/router.c index d7c1fe0..d87cdc2 100644 --- a/src/router.c +++ b/src/router.c @@ -322,7 +322,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, int flags) { +static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, 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. * @@ -367,8 +367,6 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, /* TODO: Don't store the IP stuff here. */ - *nic_bcast = iface->ipaddr->bcast; - uint32_t iface_ipaddr = iface->ipaddr->ipaddr; uint32_t iface_netmask = iface->ipaddr->netmask; @@ -575,7 +573,7 @@ static BOOL router_handle_call(struct router_vars *router, int sock, struct rout case rc_bind: { ret.ret_addr = call->arg_addr; - if(router_bind(router, sock, call->sock, &(ret.ret_addr), &(ret.ret_u32), call->arg_int) == -1) { + if(router_bind(router, sock, call->sock, &(ret.ret_addr), call->arg_int) == -1) { ret.err_code = WSAGetLastError(); } @@ -787,7 +785,7 @@ static BOOL rclient_do(struct rclient *rclient, struct router_call *call, struct return TRUE; } -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, BOOL reuse) { if(rclient->sock != -1) { struct router_call call; struct router_ret ret; @@ -803,7 +801,6 @@ BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *add if(ret.err_code == ERROR_SUCCESS) { *addr = ret.ret_addr; - *nic_bcast = ret.ret_u32; return TRUE; }else{ @@ -811,7 +808,7 @@ BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *add return FALSE; } }else if(rclient->router) { - return router_bind(rclient->router, 0, sock, addr, nic_bcast, reuse) == 0 ? TRUE: FALSE; + return router_bind(rclient->router, 0, sock, addr, reuse) == 0 ? TRUE: FALSE; } log_printf(LOG_ERROR, "rclient_bind: No router?!"); diff --git a/src/router.h b/src/router.h index 41183c8..c6f6b48 100644 --- a/src/router.h +++ b/src/router.h @@ -118,7 +118,7 @@ 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, int flags); +BOOL rclient_bind(struct rclient *rclient, SOCKET sock, struct sockaddr_ipx *addr, 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); diff --git a/src/winsock.c b/src/winsock.c index 3f57e87..2340308 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -249,7 +249,7 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) { RETURN_WSA(WSAEINVAL, -1); } - if(!rclient_bind(&g_rclient, fd, &ipxaddr, &(ptr->nic_bcast), ptr->flags)) { + if(!rclient_bind(&g_rclient, fd, &ipxaddr, ptr->flags)) { RETURN(-1); } @@ -708,6 +708,28 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval, return r_setsockopt(fd, level, optname, optval, optlen); } +/* Send an IPX packet to the specified address. + * Returns true on success, false on failure. +*/ +static int send_packet(const ipx_packet *packet, int len, struct sockaddr *addr, int addrlen) +{ + if(min_log_level <= LOG_DEBUG && addr->sa_family == AF_INET) + { + struct sockaddr_in *v4 = (struct sockaddr_in*)(addr); + + IPX_STRING_ADDR( + addr_s, + addr32_in(packet->dest_net), + addr48_in(packet->dest_node), + packet->dest_socket + ); + + log_printf(LOG_DEBUG, "Sending packet to %s (%s)", addr_s, inet_ntoa(v4->sin_addr)); + } + + return (r_sendto(send_fd, (char*)packet, len, 0, addr, addrlen) == len); +} + int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen) { struct sockaddr_ipx_ext *ipxaddr = (struct sockaddr_ipx_ext*)addr; @@ -780,36 +802,84 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s SOCKADDR_STORAGE send_addr; size_t addrlen; - if(!addr_cache_get(&send_addr, &addrlen, addr32_in(packet->dest_net), addr48_in(packet->dest_node), packet->dest_socket)) + int success = 0; + + if(addr_cache_get(&send_addr, &addrlen, addr32_in(packet->dest_net), addr48_in(packet->dest_node), packet->dest_socket)) { + /* Address is cached. We can send to the real host. */ + + success = send_packet( + packet, + psize, + (struct sockaddr*)(&send_addr), + addrlen + ); + } + else{ /* No cached address. Send using broadcast. */ - struct sockaddr_in *bcast = (struct sockaddr_in*)&send_addr; + struct sockaddr_in bcast; - bcast->sin_family = AF_INET; - bcast->sin_addr.s_addr = (main_config.bcast_all ? INADDR_BROADCAST : sockptr->nic_bcast); - bcast->sin_port = htons(main_config.udp_port); + bcast.sin_family = AF_INET; + bcast.sin_port = htons(main_config.udp_port); - addrlen = sizeof(*bcast); - } - - if(min_log_level <= LOG_DEBUG) { - /* TODO: Generic address display */ - - struct sockaddr_in *v4 = (struct sockaddr_in*)&send_addr; - - IPX_STRING_ADDR(addr_s, addr32_in(packet->dest_net), addr48_in(packet->dest_node), packet->dest_socket); - - log_printf(LOG_DEBUG, "Sending packet to %s (%s)", addr_s, inet_ntoa(v4->sin_addr)); - } - - int sval = r_sendto(send_fd, (char*)packet, psize, 0, (struct sockaddr*)&send_addr, addrlen); - if(sval == -1) { - len = -1; + if(main_config.bcast_all) + { + /* Broadcast on all interfaces. */ + + bcast.sin_addr.s_addr = htonl(INADDR_BROADCAST); + + success = send_packet( + packet, + psize, + (struct sockaddr*)(&bcast), + sizeof(bcast) + ); + } + else{ + /* Broadcast on associated interfaces. */ + + ipx_interface_t *iface = ipx_interface_by_addr( + addr32_in(packet->src_net), + addr48_in(packet->src_node) + ); + + if(iface && iface->ipaddr) + { + /* Iterate over all the IPs associated + * with this interface and return + * success if the packet makes it out + * through any of them. + */ + + ipx_interface_ip_t* ip; + + DL_FOREACH(iface->ipaddr, ip) + { + bcast.sin_addr.s_addr = ip->bcast; + + success |= send_packet( + packet, + psize, + (struct sockaddr*)(&bcast), + sizeof(bcast) + ); + } + } + else{ + /* No IP addresses. */ + + WSASetLastError(WSAENETDOWN); + success = 0; + } + + free_ipx_interface(iface); + } } free(packet); - RETURN(len); + + RETURN(success ? len : -1); }else{ return r_sendto(fd, buf, len, flags, addr, addrlen); }