int ipv4_output(struct reply *reply, struct request *req) { unsigned short len; u_int32_t sum; if (reply->off <= 0) fatalx("bad reply offset"); len = sizeof reply->pkt.bootp + reply->off; reply->pkt.l3.ip_v = 4; reply->pkt.l3.ip_hl = 5; reply->pkt.l3.ip_ttl = 16; reply->pkt.l3.ip_len = htons(len + sizeof reply->pkt.l3 + sizeof reply->pkt.l4); reply->pkt.l3.ip_tos = IPTOS_LOWDELAY; reply->pkt.l3.ip_p = IPPROTO_UDP; reply->pkt.l3.ip_src = ipv4_addr(req->rcvd_on); reply->pkt.l3.ip_dst = destination(reply, req, &reply->pkt.l4.uh_dport); /* Fill in IPv4 checksum. */ sum = checksum(&reply->pkt.l3, sizeof reply->pkt.l3, 0); reply->pkt.l3.ip_sum = wrapsum(sum); /* Fill in UDP checksum, now that we have the IPv4 header. */ sum = ntohs(reply->pkt.l4.uh_ulen) + IPPROTO_UDP; sum = checksum(&reply->pkt.l3.ip_src, 2 * sizeof(struct in_addr), sum); sum = checksum(&reply->pkt.bootp, len, sum); sum = checksum(&reply->pkt.l4, sizeof reply->pkt.l4, sum); reply->pkt.l4.uh_sum = wrapsum(sum); return 20; }
bool netblock_match(const struct sockaddr_storage *ss1, const struct sockaddr_storage *ss2, unsigned prefix) { if (ss1 == NULL || ss2 == NULL) { return false; } if (ss1->ss_family != ss2->ss_family) { return false; } const uint8_t *addr1, *addr2; switch (ss1->ss_family) { case AF_INET: addr1 = ipv4_addr(ss1); addr2 = ipv4_addr(ss2); prefix = prefix > IPV4_PREFIXLEN ? IPV4_PREFIXLEN : prefix; break; case AF_INET6: addr1 = ipv6_addr(ss1); addr2 = ipv6_addr(ss2); prefix = prefix > IPV6_PREFIXLEN ? IPV6_PREFIXLEN : prefix; break; default: return false; } /* Compare full bytes address block. */ uint8_t full_bytes = prefix / 8; for (int i = 0; i < full_bytes; i++) { if (addr1[i] != addr2[i]) { return false; } } /* Compare last partial byte address block. */ uint8_t rest_bits = prefix % 8; if (rest_bits > 0) { uint8_t rest1 = addr1[full_bytes] >> (8 - rest_bits); uint8_t rest2 = addr2[full_bytes] >> (8 - rest_bits); if (rest1 != rest2) { return false; } }
int port(struct sockaddr_storage *addr) { if (AF_INET == addr->ss_family) { return ntohs(ipv4_addr(addr)->sin_port); } else if (AF_INET6 == addr->ss_family) { return ntohs(ipv6_addr(addr)->sin6_port); } return 0; }
const char *inet_ntop(struct sockaddr_storage *addr) { if (AF_INET == addr->ss_family) { return ::inet_ntop(AF_INET, &(ipv4_addr(addr)->sin_addr), m_buffer, sizeof(m_buffer)); } else if (AF_INET6 == addr->ss_family) { return ::inet_ntop(AF_INET6, &(ipv6_addr(addr)->sin6_addr), m_buffer, sizeof(m_buffer)); } return NULL; }