- source=ntohl(*(uint32_t *)(st->buff->start+12));
- dest=ntohl(*(uint32_t *)(st->buff->start+16));
-
-/* printf("process_local_packet source=%s dest=%s len=%d\n",
- ipaddr_to_string(source),ipaddr_to_string(dest),
- st->buff->size); */
- if (!subnet_match(&st->networks,source)) {
- string_t s,d;
- s=ipaddr_to_string(source);
- d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: outgoing packet with bad source address "
- "(s=%s,d=%s)\n",st->name,s,d);
- free(s); free(d);
- return;
- }
- for (c=st->clients; c; c=c->next) {
- if (subnet_match(c->networks,dest)) {
- c->deliver(c->dst,c,st->buff);
- BUF_ALLOC(st->buff,"netlink:process_local_packet");
- return;
- }
- }
- if (dest==st->secnet_address) {
- printf("%s: secnet received packet of len %d from %s\n",st->name,
- st->buff->size,ipaddr_to_string(source));
- return;
- }
- {
- string_t s,d;
- s=ipaddr_to_string(source);
- d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: outgoing packet with bad destination address "
- "(s=%s,d=%s)\n",st->name,s,d);
- free(s); free(d);
- return;
+ len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
+ h->check=0;
+ h->check=ip_csum(&h->type,len);
+}
+
+/* RFC1122:
+ * An ICMP error message MUST NOT be sent as the result of
+ * receiving:
+ *
+ * * an ICMP error message, or
+ *
+ * * a datagram destined to an IP broadcast or IP multicast
+ * address, or
+ *
+ * * a datagram sent as a link-layer broadcast, or
+ *
+ * * a non-initial fragment, or
+ *
+ * * a datagram whose source address does not define a single
+ * host -- e.g., a zero address, a loopback address, a
+ * broadcast address, a multicast address, or a Class E
+ * address.
+ */
+static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
+{
+ struct iphdr *iph;
+ uint32_t source;
+
+ iph=(struct iphdr *)buf->start;
+ if (iph->protocol==1) return False; /* Overly-broad; we may reply to
+ eg. icmp echo-request */
+ /* How do we spot broadcast destination addresses? */
+ if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
+ source=ntohl(iph->saddr);
+ if (source==0) return False;
+ if ((source&0xff000000)==0x7f000000) return False;
+ /* How do we spot broadcast source addresses? */
+ if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
+ if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
+ return True;
+}
+
+/* How much of the original IP packet do we include in its ICMP
+ response? The header plus up to 64 bits. */
+static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ uint16_t hlen,plen;
+
+ hlen=iph->ihl*4;
+ /* We include the first 8 bytes of the packet data, provided they exist */
+ hlen+=8;
+ plen=ntohs(iph->tot_len);
+ return (hlen>plen?plen:hlen);
+}
+
+/* client indicates where the packet we're constructing a response to
+ comes from. NULL indicates the host. */
+static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
+ struct netlink_client *client,
+ uint8_t type, uint8_t code)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ struct icmphdr *h;
+ uint16_t len;
+
+ if (netlink_icmp_may_reply(buf)) {
+ len=netlink_icmp_reply_len(buf);
+ h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
+ h->type=type; h->code=code;
+ memcpy(buf_append(&st->icmp,len),buf->start,len);
+ netlink_icmp_csum(h);
+ netlink_packet_deliver(st,NULL,&st->icmp);
+ BUF_ASSERT_FREE(&st->icmp);