/* * Zero off the host bits in an address, leaving * only the network bits, using the netbits member of * struct mroute_addr as the controlling parameter. * * TODO: this is called for route-lookup for every yet-unhashed * destination address, so for lots of active net-iroutes, this * might benefit from some "zeroize 32 bit at a time" improvements */ void mroute_addr_mask_host_bits (struct mroute_addr *ma) { in_addr_t addr = ntohl(*(in_addr_t*)ma->addr); if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) { addr &= netbits_to_netmask (ma->netbits); *(in_addr_t*)ma->addr = htonl (addr); } else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) { int byte = ma->len-1; /* rightmost byte in address */ int bits_to_clear = 128 - ma->netbits; while( byte >= 0 && bits_to_clear > 0 ) { if ( bits_to_clear >= 8 ) { ma->addr[byte--] = 0; bits_to_clear -= 8; } else { ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; } } ASSERT( bits_to_clear == 0 ); } else ASSERT(0); }
/* * Zero off the host bits in an address, leaving * only the network bits, using the netbits member of * struct mroute_addr as the controlling parameter. * * TODO: this is called for route-lookup for every yet-unhashed * destination address, so for lots of active net-iroutes, this * might benefit from some "zeroize 32 bit at a time" improvements */ void mroute_addr_mask_host_bits(struct mroute_addr *ma) { if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) { in_addr_t addr = ntohl(ma->v4.addr); addr &= netbits_to_netmask(ma->netbits); ma->v4.addr = htonl(addr); } else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) { int byte = sizeof(ma->v6.addr) - 1; /* rightmost byte in address */ int bits_to_clear = 128 - ma->netbits; while (byte >= 0 && bits_to_clear > 0) { if (bits_to_clear >= 8) { ma->v6.addr.s6_addr[byte--] = 0; bits_to_clear -= 8; } else { ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); bits_to_clear = 0; } } ASSERT( bits_to_clear == 0 ); } else { ASSERT(0); } }
const char * mroute_addr_print_ex (const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (64, gc); if (ma) { struct mroute_addr maddr = *ma; switch (maddr.type & MR_ADDR_MASK) { case MR_ADDR_ETHER: buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); break; case MR_ADDR_IPV4: { struct buffer buf; in_addr_t addr; int port; bool status; buf_set_read (&buf, maddr.addr, maddr.len); addr = buf_read_u32 (&buf, &status); if (status) { if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) buf_printf (&out, "ARP/"); buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); if (maddr.type & MR_WITH_NETBITS) { if (flags & MAPF_SUBNET) { const in_addr_t netmask = netbits_to_netmask (maddr.netbits); buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc)); } else buf_printf (&out, "/%d", maddr.netbits); } } if (maddr.type & MR_WITH_PORT) { port = buf_read_u16 (&buf); if (port >= 0) buf_printf (&out, ":%d", port); } } break; case MR_ADDR_IPV6: buf_printf (&out, "IPV6"); break; default: buf_printf (&out, "UNKNOWN"); break; } return BSTR (&out); } else return "[NULL]"; }
/* * Zero off the host bits in an address, leaving * only the network bits, using the netbits member of * struct mroute_addr as the controlling parameter. */ void mroute_addr_mask_host_bits (struct mroute_addr *ma) { in_addr_t addr = ntohl(*(in_addr_t*)ma->addr); ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4); addr &= netbits_to_netmask (ma->netbits); *(in_addr_t*)ma->addr = htonl (addr); }
/* * Remove iroutes from the push_list. */ void remove_iroutes_from_push_route_list(struct options *o) { if (o && o->push_list.head && o->iroutes) { struct gc_arena gc = gc_new(); struct push_entry *e = o->push_list.head; /* cycle through the push list */ while (e) { char *p[MAX_PARMS]; bool enable = true; /* parse the push item */ CLEAR(p); if (e->enable && parse_line(e->option, p, SIZE(p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) { /* is the push item a route directive? */ if (p[0] && !strcmp(p[0], "route") && !p[3]) { /* get route parameters */ bool status1, status2; const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL); /* did route parameters parse correctly? */ if (status1 && status2) { const struct iroute *ir; /* does route match an iroute? */ for (ir = o->iroutes; ir != NULL; ir = ir->next) { if (network == ir->network && netmask == netbits_to_netmask(ir->netbits >= 0 ? ir->netbits : 32)) { enable = false; break; } } } } /* should we copy the push item? */ e->enable = enable; if (!enable) { msg(D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); } } e = e->next; } gc_free(&gc); } }
static bool add_subnet(const char *line, const char *prefix, const int line_num, struct pf_subnet ***next, const bool exclude) { struct in_addr network; in_addr_t netmask = 0; if (strcmp(line, "unknown")) { int netbits = 32; char *div = strchr(line, '/'); if (div) { *div++ = '\0'; if (sscanf(div, "%d", &netbits) != 1) { msg(D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: '%s'", prefix, line_num, div); return false; } if (netbits < 0 || netbits > 32) { msg(D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", prefix, line_num, div); return false; } } if (openvpn_inet_aton(line, &network) != OIA_IP) { msg(D_PF_INFO, "PF: %s/%d: bad network address: '%s'", prefix, line_num, line); return false; } netmask = netbits_to_netmask(netbits); if ((network.s_addr & htonl(netmask)) != network.s_addr) { network.s_addr &= htonl(netmask); msg(M_WARN, "WARNING: PF: %s/%d: incorrect subnet %s/%d changed to %s/%d", prefix, line_num, line, netbits, inet_ntoa(network), netbits); } } else { /* match special "unknown" tag for addresses unrecognized by mroute */ network.s_addr = htonl(0); netmask = IPV4_NETMASK_HOST; } { struct pf_subnet *e; ALLOC_OBJ_CLEAR(e, struct pf_subnet); e->rule.exclude = exclude; e->rule.network = ntohl(network.s_addr); e->rule.netmask = netmask; **next = e; *next = &e->next; return true; } }
static const char * print_netmask (int netbits, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (128, gc); const in_addr_t netmask = netbits_to_netmask (netbits); buf_printf (&out, "%s (/%d)", print_in_addr_t (netmask, 0, gc), netbits); return BSTR (&out); }
const char * mroute_addr_print_ex (const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (64, gc); if (ma) { struct mroute_addr maddr = *ma; switch (maddr.type & MR_ADDR_MASK) { case MR_ADDR_ETHER: buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); break; case MR_ADDR_IPV4: { struct buffer buf; in_addr_t addr; int port; bool status; buf_set_read (&buf, maddr.addr, maddr.len); addr = buf_read_u32 (&buf, &status); if (status) { if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) buf_printf (&out, "ARP/"); buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); if (maddr.type & MR_WITH_NETBITS) { if (flags & MAPF_SUBNET) { const in_addr_t netmask = netbits_to_netmask (maddr.netbits); buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc)); } else buf_printf (&out, "/%d", maddr.netbits); } } if (maddr.type & MR_WITH_PORT) { port = buf_read_u16 (&buf); if (port >= 0) buf_printf (&out, ":%d", port); } } break; case MR_ADDR_IPV6: #ifdef USE_PF_INET6 { struct buffer buf; struct sockaddr_in6 sin6; int port; char buf6[INET6_ADDRSTRLEN] = ""; CLEAR(sin6); sin6.sin6_family = AF_INET6; buf_set_read (&buf, maddr.addr, maddr.len); if (buf_read(&buf, &sin6.sin6_addr, sizeof (sin6.sin6_addr))) { if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), buf6, sizeof (buf6), NULL, 0, NI_NUMERICHOST) != 0) { buf_printf (&out, "MR_ADDR_IPV6 getnameinfo() err"); break; } buf_puts (&out, buf6); if (maddr.type & MR_WITH_NETBITS) buf_printf (&out, "/%d", maddr.netbits); if (maddr.type & MR_WITH_PORT) { port = buf_read_u16 (&buf); if (port >= 0) buf_printf (&out, ":%d", port); } } } #else /* old, pre USE_PF_INET6 code */ buf_printf (&out, "IPV6"); #endif break; default: buf_printf (&out, "UNKNOWN"); break; } return BSTR (&out); } else return "[NULL]"; }
const char * mroute_addr_print_ex(const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc) { struct buffer out = alloc_buf_gc(64, gc); if (ma) { struct mroute_addr maddr = *ma; switch (maddr.type & MR_ADDR_MASK) { case MR_ADDR_ETHER: buf_printf(&out, "%s", format_hex_ex(ma->eth_addr, sizeof(ma->eth_addr), 0, 1, ":", gc)); break; case MR_ADDR_IPV4: { if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) { buf_printf(&out, "ARP/"); } buf_printf(&out, "%s", print_in_addr_t(ntohl(maddr.v4.addr), (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); if (maddr.type & MR_WITH_NETBITS) { if (flags & MAPF_SUBNET) { const in_addr_t netmask = netbits_to_netmask(maddr.netbits); buf_printf(&out, "/%s", print_in_addr_t(netmask, 0, gc)); } else { buf_printf(&out, "/%d", maddr.netbits); } } if (maddr.type & MR_WITH_PORT) { buf_printf(&out, ":%d", ntohs(maddr.v4.port)); } } break; case MR_ADDR_IPV6: { if (IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) ) { buf_printf(&out, "%s", print_in_addr_t(maddr.v4mappedv6.addr, IA_NET_ORDER, gc)); /* we only print port numbers for v4mapped v6 as of * today, because "v6addr:port" is too ambiguous */ if (maddr.type & MR_WITH_PORT) { buf_printf(&out, ":%d", ntohs(maddr.v6.port)); } } else { buf_printf(&out, "%s", print_in6_addr(maddr.v6.addr, 0, gc)); } if (maddr.type & MR_WITH_NETBITS) { buf_printf(&out, "/%d", maddr.netbits); } } break; default: buf_printf(&out, "UNKNOWN"); break; } return BSTR(&out); } else { return "[NULL]"; } }