/** * Check if "dst" is an IPv4 address that proxy remaps to host's * loopback. */ static int proxy_ip4_is_mapped_loopback(struct netif *netif, const ip_addr_t *dst, ip_addr_t *lo) { u32_t off; const struct ip4_lomap *lomap; size_t i; LWIP_ASSERT1(dst != NULL); if (g_proxy_options->lomap_desc == NULL) { return 0; } if (!ip_addr_netcmp(dst, &netif->ip_addr, &netif->netmask)) { return 0; } /* XXX: TODO: check netif is a proxying netif! */ off = ntohl(ip4_addr_get_u32(dst) & ~ip4_addr_get_u32(&netif->netmask)); lomap = g_proxy_options->lomap_desc->lomap; for (i = 0; i < g_proxy_options->lomap_desc->num_lomap; ++i) { if (off == lomap[i].off) { if (lo != NULL) { ip_addr_copy(*lo, lomap[i].loaddr); } return 1; } } return 0; }
/** * Determine if an address is a broadcast address on a network interface * * @param addr address to be checked * @param netif the network interface against which the address is checked * @return returns non-zero if the address is a broadcast address */ u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) { ip_addr_t ipaddr; ip4_addr_set_u32(&ipaddr, addr); /* all ones (broadcast) or all zeroes (old skool broadcast) */ if ((~addr == IPADDR_ANY) || (addr == IPADDR_ANY)) { return 1; /* no broadcast support on this network interface? */ } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { /* the given address cannot be a broadcast address * nor can we check against any broadcast addresses */ return 0; /* address matches network interface address exactly? => no broadcast */ } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { return 0; /* on the same (sub) network... */ } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) /* ...and host identifier bits are all ones? =>... */ && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { /* => network broadcast address */ return 1; } else { return 0; } }
/** * Ascii internet address interpretation routine. * The value returned is in network order. * * @param cp IP address in ascii represenation (e.g. "127.0.0.1") * @return ip address in network order */ uint32_t ipaddr_addr(const char *cp) { ip_addr_t val; if (ipaddr_aton(cp, &val)) { return ip4_addr_get_u32(&val); } return IPADDR_NONE; }
/** * Ascii internet address interpretation routine. * The value returned is in network order. * * @param cp IP address in ascii represenation (e.g. "127.0.0.1") * @return ip address in network order */ u32_t ICACHE_FLASH_ATTR ipaddr_addr(const char *cp) { ip_addr_t val; if (ipaddr_aton(cp, &val)) { return ip4_addr_get_u32(&val); } return (IPADDR_NONE); }
/** * Mapping from loopback to local network for inbound (port-forwarded) * connections. * * Copy "src" to "dst" with ip_addr_set(dst, src), but if "src" is a * host's loopback address, copy local network address that maps it to * "dst". */ int pxremap_inbound_ip4(ip_addr_t *dst, ip_addr_t *src) { struct netif *netif; const struct ip4_lomap *lomap; unsigned int i; if (ip4_addr1(src) != IP_LOOPBACKNET) { ip_addr_set(dst, src); return PXREMAP_ASIS; } if (g_proxy_options->lomap_desc == NULL) { return PXREMAP_FAILED; } #if 0 /* ?TODO: with multiple interfaces we need to consider fwspec::dst */ netif = ip_route(target); if (netif == NULL) { return PXREMAP_FAILED; } #else netif = netif_list; LWIP_ASSERT1(netif != NULL); LWIP_ASSERT1(netif->next == NULL); #endif lomap = g_proxy_options->lomap_desc->lomap; for (i = 0; i < g_proxy_options->lomap_desc->num_lomap; ++i) { if (ip_addr_cmp(src, &lomap[i].loaddr)) { ip_addr_t net; ip_addr_get_network(&net, &netif->ip_addr, &netif->netmask); ip4_addr_set_u32(dst, htonl(ntohl(ip4_addr_get_u32(&net)) + lomap[i].off)); return PXREMAP_MAPPED; } } return PXREMAP_FAILED; }
/** * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. * * @param addr ip address in network order to convert * @param buf target buffer where the string is stored * @param buflen length of buf * @return either pointer to buf which now holds the ASCII * representation of addr or NULL if buf was too small */ char * ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) { u32_t s_addr; char inv[3]; char *rp; u8_t *ap; u8_t rem; u8_t n; u8_t i; int len = 0; s_addr = ip4_addr_get_u32(addr); rp = buf; ap = (u8_t *)&s_addr; for(n = 0; n < 4; n++) { i = 0; do { rem = *ap % (u8_t)10; *ap /= (u8_t)10; inv[i++] = '0' + rem; } while(*ap); while(i--) { if (len++ >= buflen) { return NULL; } *rp++ = inv[i]; } if (len++ >= buflen) { return NULL; } *rp++ = '.'; ap++; } *--rp = 0; return buf; }
/* send a DHCP OFFER to a DHCP DISCOVER */ int sendOffer(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct dhcpOfferedAddr *lease = NULL; u_int32_t req_align, lease_time_align = server_config.lease; unsigned char *req, *lease_time; struct option_set *curr; //struct in_addr addr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) { DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); return -1; } init_packet(packet, oldpacket, DHCPOFFER); #else init_packet(&packet, oldpacket, DHCPOFFER); #endif /* ADDME: if static, short circuit */ /* the client is in our lease/offered table */ if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { if (!lease_expired(lease)) lease_time_align = lease->expires - time(0); #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = lease->yiaddr; #else packet.yiaddr = lease->yiaddr; #endif /* Or the client has a requested ip */ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && /* Don't look here (ugly hackish thing to do) */ memcpy(&req_align, req, 4) && /* and the ip is in the lease range */ ntohl(req_align) >= ntohl(server_config.start) && ntohl(req_align) <= ntohl(server_config.end) && /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ /* ADDME: or maybe in here */ lease_expired(lease)))) { #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ #else packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ #endif /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ } else { #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = find_address(0); /* try for an expired lease */ if (!packet->yiaddr) packet->yiaddr = find_address(1); #else packet.yiaddr = find_address(0); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address(1); #endif } #ifdef DHCPD_HEAP_REPLACE_STACK if(!(packet->yiaddr)) { if (packet != NULL) free(packet); #else if(!packet.yiaddr) { #endif DHCPD_LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); return -1; } #ifdef DHCPD_HEAP_REPLACE_STACK if (!add_lease(packet->chaddr, packet->yiaddr, server_config.offer_time)) { if (packet != NULL) { free(packet); packet = NULL; } #else if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { #endif DHCPD_LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned"); return -1; } if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if (lease_time_align > server_config.lease) lease_time_align = server_config.lease; } /* Make sure we aren't just using the lease time from the previous offer */ if (lease_time_align < server_config.min_lease) lease_time_align = server_config.lease; /* ADDME: end of short circuit */ #ifdef DHCPD_HEAP_REPLACE_STACK struct netif *netif = netif_find(server_config.interface); add_simple_option(packet->options, DHCP_LEASE_TIME, htonl(lease_time_align)); #ifdef __CONFIG_LWIP_V1 add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(&netif->netmask)); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(&netif->gw)); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(&netif->ip_addr)); #elif LWIP_IPV4 /* now only for IPv4 */ add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(ip_2_ip4(&netif->netmask))); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(ip_2_ip4(&netif->gw))); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(ip_2_ip4(&netif->ip_addr))); #else #error "IPv4 not support!" #endif #else add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); //addr.s_addr = packet->yiaddr; DHCPD_LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(packet->yiaddr)); int ret = send_packet(packet, 0); if (packet != NULL) { free(packet); packet = NULL; } return ret; #else add_bootp_options(&packet); addr.s_addr = packet.yiaddr; DHCPD_LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); #endif } int sendNAK(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPNAK); #else init_packet(&packet, oldpacket, DHCPNAK); #endif DEBUG(LOG_INFO, "sending NAK"); #ifdef DHCPD_HEAP_REPLACE_STACK int ret = send_packet(packet, 1); if (packet != NULL) free(packet); return ret; #else return send_packet(&packet, 1); #endif } int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct option_set *curr; unsigned char *lease_time; u_int32_t lease_time_align = server_config.lease; //struct in_addr addr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPACK); packet->yiaddr = yiaddr; #else init_packet(&packet, oldpacket, DHCPACK); packet.yiaddr = yiaddr; #endif if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if (lease_time_align > server_config.lease) lease_time_align = server_config.lease; else if (lease_time_align < server_config.min_lease) lease_time_align = server_config.lease; } #ifdef DHCPD_HEAP_REPLACE_STACK struct netif *netif = netif_find(server_config.interface); add_simple_option(packet->options, DHCP_LEASE_TIME, htonl(lease_time_align)); #ifdef __CONFIG_LWIP_V1 add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(&netif->netmask)); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(&netif->gw)); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(&netif->ip_addr)); #elif LWIP_IPV4 /* now only for IPv4 */ add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(ip_2_ip4(&netif->netmask))); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(ip_2_ip4(&netif->gw))); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(ip_2_ip4(&netif->ip_addr))); #else #error "IPv4 not support!" #endif #else add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); //addr.s_addr = packet->yiaddr; DHCPD_LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(packet->yiaddr)); int ret = 0; if (send_packet(packet, 0) < 0) ret = -1; add_lease(packet->chaddr, packet->yiaddr, lease_time_align); if (packet) free(packet); return ret; #else add_bootp_options(&packet); //addr.s_addr = packet.yiaddr; DHCPD_LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(packet->yiaddr)); if (send_packet(&packet, 0) < 0) return -1; add_lease(packet.chaddr, packet.yiaddr, lease_time_align); return 0; #endif } int send_inform(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct option_set *curr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPACK); #else init_packet(&packet, oldpacket, DHCPACK); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); int ret = send_packet(packet, 0); if (packet) free(packet); return ret; #else add_bootp_options(&packet); return send_packet(&packet, 0); #endif }