diff --git a/ethsock.c b/ethsock.c index d0c192e..c1674d4 100644 --- a/ethsock.c +++ b/ethsock.c @@ -544,18 +544,19 @@ int ethsock_list_all(void) return 0; } -int ethsock_is_same_subnet(struct ethsock *sock, struct in_addr *ipaddr, - struct in_addr *ipmask) +int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback, + void *arg) { + struct ethsock_ip_callback_args args; pcap_if_t *devs, *dev; pcap_addr_t *addr; - uint32_t ip, mask, net; + int status; if (x_pcap_findalldevs(&devs) != 0) { return -1; } - net = ipaddr->s_addr & ipmask->s_addr; + args.arg = arg; for (dev = devs; dev; dev = dev->next) { if (strcmp(sock->intf, dev->name)) { @@ -564,14 +565,20 @@ int ethsock_is_same_subnet(struct ethsock *sock, struct in_addr *ipaddr, for (addr = dev->addresses; addr; addr = addr->next) { if (addr->addr->sa_family == AF_INET) { - ip = ((struct sockaddr_in*)addr->addr)->sin_addr.s_addr; - mask = ((struct sockaddr_in*)addr->netmask)->sin_addr.s_addr; - if ((ip & mask) == net) { - return 1; + args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr; + args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr; + + status = callback(&args); + if (status <= 0) { + break; } } } + + break; } - return 0; + pcap_freealldevs(devs); + + return status <= 0 ? status : 0; } diff --git a/nmrp.c b/nmrp.c index c9cf6c2..7554929 100644 --- a/nmrp.c +++ b/nmrp.c @@ -265,6 +265,40 @@ static int mac_parse(const char *str, uint8_t *hwaddr) return 0; } +struct is_valid_ip_arg +{ + struct in_addr *ipaddr; + struct in_addr *ipmask; + int result; +}; + +static int is_valid_ip_cb(struct ethsock_ip_callback_args *args) +{ +#define SUBNET(x) ((x)->ipaddr->s_addr & (x)->ipmask->s_addr) + struct is_valid_ip_arg *arg = args->arg; + if (SUBNET(args) == SUBNET(arg)) { + arg->result = args->ipaddr->s_addr != arg->ipaddr->s_addr; + return 0; + } + + return 1; +#undef SUBNET +} + +static int is_valid_ip(struct ethsock *sock, struct in_addr *ipaddr, + struct in_addr *ipmask) +{ + int status; + struct is_valid_ip_arg arg = { + .ipaddr = ipaddr, + .ipmask = ipmask, + .result = 0 + }; + + status = ethsock_for_each_ip(sock, is_valid_ip_cb, &arg); + return status < 0 ? status : arg.result; +} + static struct ethsock *gsock = NULL; static void sigh(int sig) @@ -331,13 +365,13 @@ int nmrp_do(struct nmrpd_args *args) return 1; } - status = ethsock_is_same_subnet(sock, &ipaddr, &ipmask); + status = is_valid_ip(sock, &ipaddr, &ipmask); if (status <= 0) { if (!status) { - fprintf(stderr, "Address %s/%s invalid for interface %s.\n", + fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n", args->ipaddr, args->ipmask, args->intf); } - return 1; + goto out; } gsock = sock; @@ -494,6 +528,16 @@ int nmrp_do(struct nmrpd_args *args) } if (!status && args->file_local) { + status = is_valid_ip(sock, &ipaddr, &ipmask); + if (status < 0) { + goto out; + } else if (!status) { + printf("IP address of %s has changed. Please assign a " + "static ip to the interface.\n", args->intf); + tx.msg.code = NMRP_C_CLOSE_REQ; + break; + } + if (verbosity) { printf("Using remote filename '%s'.\n", args->file_remote); diff --git a/nmrpd.h b/nmrpd.h index f6b7765..0eabf26 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -97,6 +97,15 @@ ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len); int ethsock_set_timeout(struct ethsock *sock, unsigned msec); uint8_t *ethsock_get_hwaddr(struct ethsock *sock); int ethsock_list_all(void); -int ethsock_is_same_subnet(struct ethsock *sock, struct in_addr* ip, struct in_addr *mask); +struct ethsock_ip_callback_args +{ + struct in_addr *ipaddr; + struct in_addr *ipmask; + void *arg; +}; + +typedef int (*ethsock_ip_callback_t)(struct ethsock_ip_callback_args *args); +int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback, + void *arg); #endif