int pico_network_receive(struct pico_frame *f) { if (0) {} #ifdef PICO_SUPPORT_IPV4 else if (IS_IPV4(f)) { pico_enqueue(pico_proto_ipv4.q_in, f); } #endif #ifdef PICO_SUPPORT_IPV6 else if (IS_IPV6(f)) { pico_enqueue(pico_proto_ipv6.q_in, f); } #endif else { dbg("Network not found.\n"); pico_frame_discard(f); return -1; } return f->buffer_len; }
/* PF_BRIDGE/POST_ROUTING ********************************************/ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct net_device *realoutdev = bridge_parent(skb->dev); u_int8_t pf; if (!nf_bridge || !(nf_bridge->mask & BRNF_BRIDGED)) return NF_ACCEPT; if (!realoutdev) return NF_DROP; if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) pf = PF_INET; else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) pf = PF_INET6; else return NF_ACCEPT; /* We assume any code from br_dev_queue_push_xmit onwards doesn't care * about the value of skb->pkt_type. */ if (skb->pkt_type == PACKET_OTHERHOST) { skb->pkt_type = PACKET_HOST; nf_bridge->mask |= BRNF_PKT_TYPE; } nf_bridge_pull_encap_header(skb); nf_bridge_save_header(skb); if (pf == PF_INET) skb->protocol = htons(ETH_P_IP); else skb->protocol = htons(ETH_P_IPV6); NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev, br_nf_dev_queue_xmit); return NF_STOLEN; }
const char * sockporttoa( const sockaddr_u *sock ) { int saved_errno; const char * atext; char * buf; saved_errno = errno; atext = socktoa(sock); LIB_GETBUF(buf); snprintf(buf, LIB_BUFLENGTH, (IS_IPV6(sock)) ? "[%s]:%hu" : "%s:%hu", atext, SRCPORT(sock)); errno = saved_errno; return buf; }
int pico_source_is_local(struct pico_frame *f) { if (0) { } #ifdef PICO_SUPPORT_IPV4 else if (IS_IPV4(f)) { struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; if (hdr->src.addr == PICO_IPV4_INADDR_ANY) return 1; if (pico_ipv4_link_find(&hdr->src)) return 1; } #endif #ifdef PICO_SUPPORT_IPV6 else if (IS_IPV6(f)) { /* XXX */ } #endif return 0; }
static int destination_is_mcast(struct pico_frame *f) { int ret = 0; if (!f) return 0; #ifdef PICO_SUPPORT_IPV6 if (IS_IPV6(f)) { struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *) f->net_hdr; ret = pico_ipv6_is_multicast(hdr->dst.addr); } #endif #ifdef PICO_SUPPORT_IPV4 else { struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; ret = pico_ipv4_is_multicast(hdr->dst.addr); } #endif return ret; }
static int cmp_prefer_ipv6 (const void *addr1, const void *addr2) { return !IS_IPV6 (addr1) - !IS_IPV6 (addr2); }
/* This is the 'purely bridged' case. For IP, we pass the packet to * netfilter with indev and outdev set to the bridge device, * but we are still able to filter on the 'real' indev/outdev * because of the physdev module. For ARP, indev and outdev are the * bridge ports. */ static unsigned int br_nf_forward_ip(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct nf_bridge_info *nf_bridge; struct net_device *parent; u_int8_t pf; if (!skb->nf_bridge) return NF_ACCEPT; /* Need exclusive nf_bridge_info since we might have multiple * different physoutdevs. */ if (!nf_bridge_unshare(skb)) return NF_DROP; nf_bridge = nf_bridge_info_get(skb); if (!nf_bridge) return NF_DROP; parent = bridge_parent(state->out); if (!parent) return NF_DROP; if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) pf = NFPROTO_IPV4; else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) pf = NFPROTO_IPV6; else return NF_ACCEPT; nf_bridge_pull_encap_header(skb); if (skb->pkt_type == PACKET_OTHERHOST) { skb->pkt_type = PACKET_HOST; nf_bridge->pkt_otherhost = true; } if (pf == NFPROTO_IPV4) { if (br_validate_ipv4(state->net, skb)) return NF_DROP; IPCB(skb)->frag_max_size = nf_bridge->frag_max_size; } if (pf == NFPROTO_IPV6) { if (br_validate_ipv6(state->net, skb)) return NF_DROP; IP6CB(skb)->frag_max_size = nf_bridge->frag_max_size; } nf_bridge->physoutdev = skb->dev; if (pf == NFPROTO_IPV4) skb->protocol = htons(ETH_P_IP); else skb->protocol = htons(ETH_P_IPV6); NF_HOOK(pf, NF_INET_FORWARD, state->net, NULL, skb, brnf_get_logical_dev(skb, state->in), parent, br_nf_forward_finish); return NF_STOLEN; }
/* Receive data from broadcast. Couldn't finish that. Need to do some digging * here, especially for protocol independence and IPv6 multicast */ int recv_bcst_data ( SOCKET rsock, char *rdata, int rdata_len, sockaddr_u *sas, sockaddr_u *ras ) { char *buf; int btrue = 1; int recv_bytes = 0; int rdy_socks; GETSOCKNAME_SOCKLEN_TYPE ss_len; struct timeval timeout_tv; fd_set bcst_fd; #ifdef MCAST struct ip_mreq mdevadr; TYPEOF_IP_MULTICAST_LOOP mtrue = 1; #endif #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT struct ipv6_mreq mdevadr6; #endif setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue)); if (IS_IPV4(sas)) { if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n", stoa(sas), SRCPORT(sas)); } #ifdef MCAST if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) { /* some error message regarding setting up multicast loop */ return BROADCAST_FAILED; } mdevadr.imr_multiaddr.s_addr = NSRCADR(sas); mdevadr.imr_interface.s_addr = htonl(INADDR_ANY); if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) { if (ENABLED_OPT(NORMALVERBOSE)) { printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n", stoa(sas), SRCPORT(sas)); } return BROADCAST_FAILED; } if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf); free(buf); } } #endif /* MCAST */ } #ifdef ISC_PLATFORM_HAVEIPV6 else if (IS_IPV6(sas)) { if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: Couldn't bind() address.\n"); } #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) { /* some error message regarding setting up multicast loop */ return BROADCAST_FAILED; } memset(&mdevadr6, 0, sizeof(mdevadr6)); mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas); if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf); free(buf); } return BROADCAST_FAILED; } if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mdevadr6, sizeof(mdevadr6)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf); free(buf); } } #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ } #endif /* ISC_PLATFORM_HAVEIPV6 */ FD_ZERO(&bcst_fd); FD_SET(rsock, &bcst_fd); if (ENABLED_OPT(TIMEOUT)) timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT)); else timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */ timeout_tv.tv_usec = 0; rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv); switch (rdy_socks) { case -1: if (ENABLED_OPT(NORMALVERBOSE)) perror("sntp recv_bcst_data: select()"); return BROADCAST_FAILED; break; case 0: if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n", (unsigned)timeout_tv.tv_sec); return BROADCAST_FAILED; break; default: ss_len = sizeof(*ras); recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len); break; } if (recv_bytes == -1) { if (ENABLED_OPT(NORMALVERBOSE)) perror("sntp recv_bcst_data: recvfrom:"); recv_bytes = BROADCAST_FAILED; } #ifdef MCAST if (IS_IPV4(sas)) setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue)); #endif #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (IS_IPV6(sas)) setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue)); #endif return recv_bytes; }
/* ** queue_xmt */ void queue_xmt( SOCKET sock, struct dns_ctx * dctx, sent_pkt * spkt, u_int xmt_delay ) { sockaddr_u * dest; sent_pkt ** pkt_listp; sent_pkt * match; xmt_ctx * xctx; struct timeval start_cb; struct timeval delay; dest = &spkt->addr; if (IS_IPV6(dest)) pkt_listp = &v6_pkts_list; else pkt_listp = &v4_pkts_list; /* reject attempts to add address already listed */ for (match = *pkt_listp; match != NULL; match = match->link) { if (ADDR_PORT_EQ(&spkt->addr, &match->addr)) { if (strcasecmp(spkt->dctx->name, match->dctx->name)) printf("%s %s duplicate address from %s ignored.\n", sptoa(&match->addr), match->dctx->name, spkt->dctx->name); else printf("%s %s, duplicate address ignored.\n", sptoa(&match->addr), match->dctx->name); dec_pending_ntp(spkt->dctx->name, &spkt->addr); free(spkt); return; } } LINK_SLIST(*pkt_listp, spkt, link); xctx = emalloc_zero(sizeof(*xctx)); xctx->sock = sock; xctx->spkt = spkt; gettimeofday_cached(base, &start_cb); xctx->sched = start_cb.tv_sec + (2 * xmt_delay); LINK_SORT_SLIST(xmt_q, xctx, (xctx->sched < L_S_S_CUR()->sched), link, xmt_ctx); if (xmt_q == xctx) { /* * The new entry is the first scheduled. The timer is * either not active or is set for the second xmt * context in xmt_q. */ if (NULL == ev_xmt_timer) ev_xmt_timer = event_new(base, INVALID_SOCKET, EV_TIMEOUT, &xmt_timer_cb, NULL); if (NULL == ev_xmt_timer) { msyslog(LOG_ERR, "queue_xmt: event_new(base, -1, EV_TIMEOUT) failed!"); exit(1); } ZERO(delay); if (xctx->sched > start_cb.tv_sec) delay.tv_sec = xctx->sched - start_cb.tv_sec; event_add(ev_xmt_timer, &delay); TRACE(2, ("queue_xmt: xmt timer for %u usec\n", (u_int)delay.tv_usec)); } }
/* * hack_restrict - add/subtract/manipulate entries on the restrict list */ void hack_restrict( int op, sockaddr_u * resaddr, sockaddr_u * resmask, u_short mflags, u_short flags, u_long expire ) { int v6; restrict_u match; restrict_u * res; restrict_u ** plisthead; DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n", op, stoa(resaddr), stoa(resmask), mflags, flags)); if (NULL == resaddr) { REQUIRE(NULL == resmask); REQUIRE(RESTRICT_FLAGS == op); restrict_source_flags = flags; restrict_source_mflags = mflags; restrict_source_enabled = 1; return; } ZERO(match); #if 0 /* silence VC9 potentially uninit warnings */ // HMS: let's use a compiler-specific "enable" for this. res = NULL; v6 = 0; #endif if (IS_IPV4(resaddr)) { v6 = 0; /* * Get address and mask in host byte order for easy * comparison as u_int32 */ match.u.v4.addr = SRCADR(resaddr); match.u.v4.mask = SRCADR(resmask); match.u.v4.addr &= match.u.v4.mask; } else if (IS_IPV6(resaddr)) { v6 = 1; /* * Get address and mask in network byte order for easy * comparison as byte sequences (e.g. memcmp()) */ match.u.v6.mask = SOCK_ADDR6(resmask); MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), &match.u.v6.mask); } else /* not IPv4 nor IPv6 */ REQUIRE(0); match.flags = flags; match.mflags = mflags; match.expire = expire; res = match_restrict_entry(&match, v6); switch (op) { case RESTRICT_FLAGS: /* * Here we add bits to the flags. If this is a * new restriction add it. */ if (NULL == res) { if (v6) { res = alloc_res6(); memcpy(res, &match, V6_SIZEOF_RESTRICT_U); plisthead = &restrictlist6; } else { res = alloc_res4(); memcpy(res, &match, V4_SIZEOF_RESTRICT_U); plisthead = &restrictlist4; } LINK_SORT_SLIST( *plisthead, res, (v6) ? res_sorts_before6(res, L_S_S_CUR()) : res_sorts_before4(res, L_S_S_CUR()), link, restrict_u); restrictcount++; if (RES_LIMITED & flags) inc_res_limited(); } else { if ((RES_LIMITED & flags) && !(RES_LIMITED & res->flags)) inc_res_limited(); res->flags |= flags; } break; case RESTRICT_UNFLAG: /* * Remove some bits from the flags. If we didn't * find this one, just return. */ if (res != NULL) { if ((RES_LIMITED & res->flags) && (RES_LIMITED & flags)) dec_res_limited(); res->flags &= ~flags; } break; case RESTRICT_REMOVE: case RESTRICT_REMOVEIF: /* * Remove an entry from the table entirely if we * found one. Don't remove the default entry and * don't remove an interface entry. */ if (res != NULL && (RESTRICT_REMOVEIF == op || !(RESM_INTERFACE & res->mflags)) && res != &restrict_def4 && res != &restrict_def6) free_res(res, v6); break; default: /* unknown op */ INSIST(0); break; } }
/* * restrictions - return restrictions for this host */ u_short restrictions( sockaddr_u *srcadr ) { restrict_u *match; struct in6_addr *pin6; u_short flags; res_calls++; flags = 0; /* IPv4 source address */ if (IS_IPV4(srcadr)) { /* * Ignore any packets with a multicast source address * (this should be done early in the receive process, * not later!) */ if (IN_CLASSD(SRCADR(srcadr))) return (int)RES_IGNORE; match = match_restrict4_addr(SRCADR(srcadr), SRCPORT(srcadr)); INSIST(match != NULL); match->count++; /* * res_not_found counts only use of the final default * entry, not any "restrict default ntpport ...", which * would be just before the final default. */ if (&restrict_def4 == match) res_not_found++; else res_found++; flags = match->flags; } /* IPv6 source address */ if (IS_IPV6(srcadr)) { pin6 = PSOCK_ADDR6(srcadr); /* * Ignore any packets with a multicast source address * (this should be done early in the receive process, * not later!) */ if (IN6_IS_ADDR_MULTICAST(pin6)) return (int)RES_IGNORE; match = match_restrict6_addr(pin6, SRCPORT(srcadr)); INSIST(match != NULL); match->count++; if (&restrict_def6 == match) res_not_found++; else res_found++; flags = match->flags; } return (flags); }
int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) { struct pico_eth dstmac; uint8_t dstmac_valid = 0; uint16_t proto = PICO_IDETH_IPV4; #ifdef PICO_SUPPORT_IPV6 /* Step 1: If the frame has an IPv6 packet, * destination address is taken from the ND tables */ if (IS_IPV6(f)) { if (pico_ethernet_ipv6_dst(f, &dstmac) < 0) { pico_ipv6_nd_postpone(f); return 0; /* I don't care if frame was actually postponed. If there is no room in the ND table, discard safely. */ } dstmac_valid = 1; proto = PICO_IDETH_IPV6; } else #endif /* In case of broadcast (IPV4 only), dst mac is FF:FF:... */ if (IS_BCAST(f) || destination_is_bcast(f)) { memcpy(&dstmac, PICO_ETHADDR_ALL, PICO_SIZE_ETH); dstmac_valid = 1; } /* In case of multicast, dst mac is translated from the group address */ else if (destination_is_mcast(f)) { uint8_t pico_mcast_mac[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; pico_ethernet_mcast_translate(f, pico_mcast_mac); memcpy(&dstmac, pico_mcast_mac, PICO_SIZE_ETH); dstmac_valid = 1; } #if (defined PICO_SUPPORT_IPV4) else { struct pico_eth *arp_get; arp_get = pico_arp_get(f); if (arp_get) { memcpy(&dstmac, arp_get, PICO_SIZE_ETH); dstmac_valid = 1; } else { /* At this point, ARP will discard the frame in any case. * It is safe to return without discarding. */ pico_arp_postpone(f); return 0; /* Same case as for IPv6 ... */ } } #endif /* This sets destination and source address, then pushes the packet to the device. */ if (dstmac_valid) { struct pico_eth_hdr *hdr; hdr = (struct pico_eth_hdr *) f->datalink_hdr; if ((f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR)) { f->start -= PICO_SIZE_ETHHDR; f->len += PICO_SIZE_ETHHDR; f->datalink_hdr = f->start; hdr = (struct pico_eth_hdr *) f->datalink_hdr; memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); memcpy(hdr->daddr, &dstmac, PICO_SIZE_ETH); hdr->proto = proto; } if (pico_ethsend_local(f, hdr) || pico_ethsend_bcast(f) || pico_ethsend_dispatch(f)) { /* one of the above functions has delivered the frame accordingly. (returned != 0) * It is safe to directly return success. * */ return 0; } } /* Failure: do not dequeue the frame, keep it for later. */ return -1; }
/* * restrictions - return restrictions for this host in *r4a */ void restrictions( sockaddr_u *srcadr, r4addr *r4a ) { restrict_u *match; struct in6_addr *pin6; REQUIRE(NULL != r4a); res_calls++; r4a->rflags = RES_IGNORE; r4a->ippeerlimit = 0; DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr))); /* IPv4 source address */ if (IS_IPV4(srcadr)) { /* * Ignore any packets with a multicast source address * (this should be done early in the receive process, * not later!) */ if (IN_CLASSD(SRCADR(srcadr))) { DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr))); r4a->ippeerlimit = 2; /* XXX: we should use a better value */ return; } match = match_restrict4_addr(SRCADR(srcadr), SRCPORT(srcadr)); INSIST(match != NULL); match->count++; /* * res_not_found counts only use of the final default * entry, not any "restrict default ntpport ...", which * would be just before the final default. */ if (&restrict_def4 == match) res_not_found++; else res_found++; r4a->rflags = match->rflags; r4a->ippeerlimit = match->ippeerlimit; } /* IPv6 source address */ if (IS_IPV6(srcadr)) { pin6 = PSOCK_ADDR6(srcadr); /* * Ignore any packets with a multicast source address * (this should be done early in the receive process, * not later!) */ if (IN6_IS_ADDR_MULTICAST(pin6)) return; match = match_restrict6_addr(pin6, SRCPORT(srcadr)); INSIST(match != NULL); match->count++; if (&restrict_def6 == match) res_not_found++; else res_found++; r4a->rflags = match->rflags; r4a->ippeerlimit = match->ippeerlimit; } return; }