1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Iterate over interface broadcast addresses in sendto rather than storing a

single address in ipx_socket during router bind.
This commit is contained in:
Daniel Collins 2012-11-03 12:57:34 +00:00
parent f087fc26b1
commit f72e88ea34
5 changed files with 103 additions and 32 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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?!");

View File

@ -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);

View File

@ -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);
}