Beispiel #1
0
int
ip_direction_indexer(const void *vp)
{
    const ip_message *ip = vp;
    if (ip_is_local(&ip->src))
	return 0;
    if (ip_is_local(&ip->dst))
	return 1;
    return LARGEST;
}
int
ip_direction_indexer(const void *vp)
{
    const dns_message *m = vp;
    const transport_message *tm = m->tm;
    if (ip_is_local(&tm->src_ip_addr))
	return 0;
    if (ip_is_local(&tm->dst_ip_addr))
	return 1;
    return LARGEST;
}
Beispiel #3
0
/* Add a TCP relay associated to the friend.
 *
 * return -1 on failure.
 * return 0 on success.
 */
int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key)
{
    Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id);

    if (!friend_con) {
        return -1;
    }

    /* Local ip and same pk means that they are hosting a TCP relay. */
    if (ip_is_local(ip_port.ip) && public_key_cmp(friend_con->dht_temp_pk, public_key) == 0) {
        if (!net_family_is_unspec(friend_con->dht_ip_port.ip.family)) {
            ip_port.ip = friend_con->dht_ip_port.ip;
        } else {
            friend_con->hosting_tcp_relay = 0;
        }
    }

    const uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS;

    for (unsigned i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) {
        if (!net_family_is_unspec(friend_con->tcp_relays[i].ip_port.ip.family)
                && public_key_cmp(friend_con->tcp_relays[i].public_key, public_key) == 0) {
            memset(&friend_con->tcp_relays[i], 0, sizeof(Node_format));
        }
    }

    friend_con->tcp_relays[index].ip_port = ip_port;
    memcpy(friend_con->tcp_relays[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
    ++friend_con->tcp_relay_counter;

    return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key);
}
Beispiel #4
0
/* Is IP a local ip or not. */
bool ip_is_local(IP ip)
{
    if (ip.family == TOX_AF_INET) {
        IP4 ip4 = ip.ip.v4;

        /* Loopback. */
        if (ip4.uint8[0] == 127) {
            return 1;
        }
    } else {
        /* embedded IPv4-in-IPv6 */
        if (IPV6_IPV4_IN_V6(ip.ip.v6)) {
            IP ip4;
            ip4.family = TOX_AF_INET;
            ip4.ip.v4.uint32 = ip.ip.v6.uint32[3];
            return ip_is_local(ip4);
        }

        /* localhost in IPv6 (::1) */
        if (ip.ip.v6.uint64[0] == 0 && ip.ip.v6.uint32[2] == 0 && ip.ip.v6.uint32[3] == net_htonl(1)) {
            return 1;
        }
    }

    return 0;
}
Beispiel #5
0
/*  return 0 if ip is a LAN ip.
 *  return -1 if it is not.
 */
int ip_is_lan(IP ip)
{
    if (ip_is_local(ip)) {
        return 0;
    }

    if (ip.family == TOX_AF_INET) {
        IP4 ip4 = ip.ip.v4;

        /* 10.0.0.0 to 10.255.255.255 range. */
        if (ip4.uint8[0] == 10) {
            return 0;
        }

        /* 172.16.0.0 to 172.31.255.255 range. */
        if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31) {
            return 0;
        }

        /* 192.168.0.0 to 192.168.255.255 range. */
        if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168) {
            return 0;
        }

        /* 169.254.1.0 to 169.254.254.255 range. */
        if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0
                && ip4.uint8[2] != 255) {
            return 0;
        }

        /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
         * (shared address space to stack another layer of NAT) */
        if ((ip4.uint8[0] == 100) && ((ip4.uint8[1] & 0xC0) == 0x40)) {
            return 0;
        }
    } else if (ip.family == TOX_AF_INET6) {

        /* autogenerated for each interface: FE80::* (up to FEBF::*)
           FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
        if (((ip.ip.v6.uint8[0] == 0xFF) && (ip.ip.v6.uint8[1] < 3) && (ip.ip.v6.uint8[15] == 1)) ||
                ((ip.ip.v6.uint8[0] == 0xFE) && ((ip.ip.v6.uint8[1] & 0xC0) == 0x80))) {
            return 0;
        }

        /* embedded IPv4-in-IPv6 */
        if (IPV6_IPV4_IN_V6(ip.ip.v6)) {
            IP ip4;
            ip4.family = TOX_AF_INET;
            ip4.ip.v4.uint32 = ip.ip.v6.uint32[3];
            return ip_is_lan(ip4);
        }
    }

    return -1;
}
Beispiel #6
0
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) {
	net_device_stats_t *stats = &dev->stats;
	const struct net_proto *nproto;
	iphdr_t *iph = ip_hdr(skb);
	__u16 old_check;
	size_t ip_len;
	int optlen;
	sk_buff_t *complete_skb;

	/**
	 *   RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *   Is the datagram acceptable?
	 *   1.  Length at least the size of an ip header
	 *   2.  Version of 4
	 *   3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *   4.  Doesn't have a bogus length
	 */
	if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE
			|| IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE
			|| skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) {
		DBG(printk("ip_rcv: invalid IPv4 header length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid header length */
	}


	if (iph->version != 4) {
		DBG(printk("ip_rcv: invalid IPv4 version\n"));
		stats->rx_err++;
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	old_check = iph->check;
	ip_set_check_field(iph);
	if (old_check != iph->check) {
		DBG(printk("ip_rcv: invalid checksum %hx(%hx)\n",
				ntohs(old_check), ntohs(iph->check)));
		stats->rx_crc_errors++;
		skb_free(skb);
		return 0; /* error: invalid crc */
	}

	ip_len = ntohs(iph->tot_len);
	if (ip_len < IP_HEADER_SIZE(iph)
			|| skb->len < dev->hdr_len + ip_len) {
		DBG(printk("ip_rcv: invalid IPv4 length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Setup transport layer (L4) header */
	skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph);

	/* Validating */
	if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) {
		DBG(printk("ip_rcv: dropped by input netfilter\n"));
		stats->rx_dropped++;
		skb_free(skb);
		return 0; /* error: dropped */
	}

	/* Forwarding */
	assert(skb->dev);
	assert(inetdev_get_by_dev(skb->dev));
	if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) {
		/**
		 * FIXME
		 * This check needed for BOOTP protocol
		 * disable forwarding if interface is not set yet
		 */
		/**
		 * Check the destination address, and if it doesn't match
		 * any of own addresses, retransmit packet according to the routing table.
		 */
		if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) {
			if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) {
				DBG(printk("ip_rcv: dropped by forward netfilter\n"));
				stats->rx_dropped++;
				skb_free(skb);
				return 0; /* error: dropped */
			}
			return ip_forward(skb);
		}
	}

	memset(skb->cb, 0, sizeof(skb->cb));
	optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE;
	if (optlen > 0) {
		/* NOTE : maybe it'd be better to copy skb here,
		 * 'cause options may cause modifications
		 * but smart people who wrote linux kernel
		 * say that this is extremely rarely needed
		 */
		ip_options_t *opts = (ip_options_t*)(skb->cb);

		memset(skb->cb, 0, sizeof(skb->cb));
		opts->optlen = optlen;
		if (ip_options_compile(skb, opts)) {
			DBG(printk("ip_rcv: invalid options\n"));
			stats->rx_err++;
			skb_free(skb);
			return 0; /* error: bad ops */
		}
		if (ip_options_handle_srr(skb)) {
			DBG(printk("ip_rcv: can't handle options\n"));
			stats->tx_err++;
			skb_free(skb);
			return 0; /* error: can't handle ops */
		}
	}

	/* It's very useful for us to have complete packet even for forwarding
	 * (we may apply any filter, we may perform NAT etc),
	 * but it'll break routing if different parts of a fragmented
	 * packet will use different routes. So they can't be assembled.
	 * See RFC 1812 for details
	 */
	if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) {
		if ((complete_skb = ip_defrag(skb)) == NULL) {
			if (skb == NULL) {
				return 0; /* error: */
			}
			return 0;
		} else {
			skb = complete_skb;
			iph = ip_hdr(complete_skb);
		}
	}

	/* When a packet is received, it is passed to any raw sockets
	 * which have been bound to its protocol or to socket with concrete protocol */
	raw_rcv(skb);

	nproto = net_proto_lookup(ETH_P_IP, iph->proto);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

	DBG(printk("ip_rcv: unknown protocol\n"));
	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}
Beispiel #7
0
int icmp_discard(struct sk_buff *skb, uint8_t type, uint8_t code,
		...) {
	struct {
		union {
			struct icmpbody_dest_unreach dest_unreach;
			struct icmpbody_source_quench source_quench;
			struct icmpbody_redirect redirect;
			struct icmpbody_time_exceed time_exceed;
			struct icmpbody_param_prob param_prob;
		} __attribute__((packed));
		char __body_msg_storage[ICMP_DISCARD_MAX_SIZE];
	} __attribute__((packed)) body;
	va_list extra;
	uint8_t *body_msg;
	size_t body_msg_sz;

	if (!(ip_is_local(ip_hdr(skb)->saddr, 0)
				|| ip_is_local(ip_hdr(skb)->daddr, 0))
			|| (ip_hdr(skb)->frag_off & htons(IP_OFFSET))
			|| (ip_data_length(ip_hdr(skb)) < ICMP_DISCARD_MIN_SIZE)
			|| (ip_hdr(skb)->proto != IPPROTO_ICMP)
			|| (skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(ip_hdr(skb)),
				ICMP_TYPE_ERROR(icmp_hdr(skb)->type))) {
		skb_free(skb);
		return 0; /* error: inappropriate packet */
	}

	switch (type) {
	default:
		assertf(0, "bad type for discard");
		body_msg = (uint8_t *)&body.__body_msg_storage[0];
		break; /* error: bad type for discard */
	case ICMP_DEST_UNREACH:
		assertf(code < __ICMP_DEST_UNREACH_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.dest_unreach.zero = 0;
		body.dest_unreach.mtu = code != ICMP_FRAG_NEEDED ? 0
				: htons((uint16_t)va_arg(extra, int));
		va_end(extra);
		body_msg = &body.dest_unreach.msg[0];
		break;
	case ICMP_SOURCE_QUENCH:
		assertf(code == 0, "incorrect code for type");
		body.source_quench.zero = 0;
		body_msg = &body.source_quench.msg[0];
		break;
	case ICMP_REDIRECT:
		assertf(code < __ICMP_REDIRECT_MAX,
				"incorrect code for type");
		va_start(extra, code);
		memcpy(&body.redirect.gateway,
				va_arg(extra, struct in_addr *),
				sizeof body.redirect.gateway);
		va_end(extra);
		body_msg = &body.redirect.msg[0];
		break;
	case ICMP_TIME_EXCEED:
		assertf(code < __ICMP_TIME_EXCEED_MAX,
				"incorrect code for type");
		body.time_exceed.zero = 0;
		body_msg = &body.time_exceed.msg[0];
		break;
	case ICMP_PARAM_PROB:
		assertf(code < __ICMP_PARAM_PROB_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.param_prob.ptr = code != ICMP_PTR_ERROR ? 0
				: (uint8_t)va_arg(extra, int);
		body.param_prob.zero1 = body.param_prob.zero2 = 0;
		va_end(extra);
		body_msg = &body.param_prob.msg[0];
		break;
	}

	body_msg_sz = min(ip_data_length(ip_hdr(skb)),
			sizeof body.__body_msg_storage);
	memcpy(body_msg, ip_hdr(skb), body_msg_sz);

	if (NULL == skb_declone(skb)) {
		skb_free(skb);
		return -ENOMEM; /* error: can't declone data */
	}

	return icmp_send(type, code, &body, sizeof body
				- sizeof body.__body_msg_storage + body_msg_sz,
			skb);
}