void ip_checksum(void *buf, size_t len) { struct ip *ip; int hl, off, sum; if (len < sizeof(struct ip)) return; ip = (struct ip *)buf; hl = ip->ip_hl << 2; ip->ip_sum = 0; sum = ip_cksum_add(ip, hl, 0); ip->ip_sum = ip_cksum_carry(sum); off = htons(ip->ip_off); if ((off & IP_OFFMASK) != 0 || (off & IP_MF) != 0) return; len -= hl; if (ip->ip_p == IPPROTO_UDP) { struct udphdr *udp = (struct udphdr *)((u_char *)ip + hl); if (len >= sizeof(struct udphdr)) { udp->uh_sum = 0; sum = ip_cksum_add(udp, len, 0) + htons(ip->ip_p + len); sum = ip_cksum_add(&ip->ip_src, 8, sum); udp->uh_sum = ip_cksum_carry(sum); if (!udp->uh_sum) udp->uh_sum = 0xffff; /* RFC 768 */ } } }
void ip6_checksum(void *buf, size_t len) { struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; struct ip6_ext_hdr *ext; u_char *p, nxt; int i, sum; nxt = ip6->ip6_nxt; for (i = IP6_HDR_LEN; IP6_IS_EXT(nxt); i += (ext->ext_len + 1) << 3) { if (i >= (int)len) return; ext = (struct ip6_ext_hdr *)((u_char *)buf + i); nxt = ext->ext_nxt; } p = (u_char *)buf + i; len -= i; if (nxt == IP_PROTO_TCP) { struct tcp_hdr *tcp = (struct tcp_hdr *)p; if (len >= TCP_HDR_LEN) { tcp->th_sum = 0; sum = ip_cksum_add(tcp, len, 0) + htons(nxt + (u_short)len); sum = ip_cksum_add(&ip6->ip6_src, 32, sum); tcp->th_sum = ip_cksum_carry(sum); } } else if (nxt == IP_PROTO_UDP) { struct udp_hdr *udp = (struct udp_hdr *)p; if (len >= UDP_HDR_LEN) { udp->uh_sum = 0; sum = ip_cksum_add(udp, len, 0) + htons(nxt + (u_short)len); sum = ip_cksum_add(&ip6->ip6_src, 32, sum); if ((udp->uh_sum = ip_cksum_carry(sum)) == 0) udp->uh_sum = 0xffff; } } else if (nxt == IP_PROTO_ICMPV6) { struct icmp_hdr *icmp = (struct icmp_hdr *)p; if (len >= ICMP_HDR_LEN) { icmp->icmp_cksum = 0; sum = ip_cksum_add(icmp, len, 0) + htons(nxt + (u_short)len); sum = ip_cksum_add(&ip6->ip6_src, 32, sum); icmp->icmp_cksum = ip_cksum_carry(sum); } } else if (nxt == IP_PROTO_ICMP || nxt == IP_PROTO_IGMP) { struct icmp_hdr *icmp = (struct icmp_hdr *)p; if (len >= ICMP_HDR_LEN) { icmp->icmp_cksum = 0; sum = ip_cksum_add(icmp, len, 0); icmp->icmp_cksum = ip_cksum_carry(sum); } } }
// Calculate IP checksum over the buffer : void ip_checksum(void *buf, size_t len) { struct ip_hdr *ip; int hl, off, sum; if (len < IP_HDR_LEN) return; ip = (struct ip_hdr *)buf; hl = ip->ip_hl << 2; ip->ip_sum = 0; sum = ip_cksum_add(ip, hl, 0); ip->ip_sum = ip_cksum_carry(sum); off = htons(ip->ip_off); if ((off & IP_OFFMASK) != 0 || (off & IP_MF) != 0) return; len -= hl; if (ip->ip_p == IP_PROTO_TCP) { struct tcp_hdr *tcp = (struct tcp_hdr *)((u_char *)ip + hl); if (len >= TCP_HDR_LEN) { tcp->th_sum = 0; sum = ip_cksum_add(tcp, len, 0) + htons(ip->ip_p + (unsigned short) len); sum = ip_cksum_add(&ip->ip_src, 8, sum); tcp->th_sum = ip_cksum_carry(sum); } } else if (ip->ip_p == IP_PROTO_UDP) { struct udp_hdr *udp = (struct udp_hdr *)((u_char *)ip + hl); if (len >= UDP_HDR_LEN) { udp->uh_sum = 0; sum = ip_cksum_add(udp, len, 0) + htons(ip->ip_p + (unsigned short) len); sum = ip_cksum_add(&ip->ip_src, 8, sum); udp->uh_sum = ip_cksum_carry(sum); if (!udp->uh_sum) udp->uh_sum = 0xffff; /* RFC 768 */ } } else if (ip->ip_p == IP_PROTO_ICMP || ip->ip_p == IP_PROTO_IGMP) { struct icmp_hdr *icmp = (struct icmp_hdr *)((u_char *)ip + hl); if (len >= ICMP_HDR_LEN) { icmp->icmp_cksum = 0; sum = ip_cksum_add(icmp, len, 0); icmp->icmp_cksum = ip_cksum_carry(sum); } } }
int gre_encapsulate(ip_t *honeyd_ip, struct addr *src, struct addr *dst, struct ip_hdr *iip, u_int iiplen) { struct ip_hdr *oip = (struct ip_hdr *) pkt; struct gre_hdr *gre = (struct gre_hdr *) (oip + 1); u_char *data = (u_char *) (gre + 1); u_int iplen, sum; iplen = sizeof(struct ip_hdr) + sizeof(struct gre_hdr) + iiplen; if (iplen > sizeof(pkt)) { syslog(LOG_ERR, "%s: packet too long: %d", __func__, iplen); return (-1); } ip_pack_hdr(pkt, 0, iplen, rand_uint16(honeyd_rand), 0, honeyd_ttl, IP_PROTO_GRE, src->addr_ip, dst->addr_ip); memset(gre, 0, sizeof(struct gre_hdr)); gre->gre_flags = htons(GRE_CHECKSUM | GRE_VERSION); gre->gre_proto = htons(GRE_IP4PROTO); /* Copy the payload */ memcpy(data, iip, iiplen); /* Calculate the checksum */ sum = ip_cksum_add(gre, iiplen + sizeof(struct gre_hdr), 0); gre->gre_sum = ip_cksum_carry(sum); ip_checksum(oip, iplen); return (ip_send(honeyd_ip, pkt, iplen) != iplen ? -1 : 0); }
int gre_decapsulate(struct ip_hdr *oip, u_short oiplen, struct ip_hdr **pip, u_short *piplen) { struct gre_hdr *gre; struct ip_hdr *ip; u_char *end = (u_char *) oip + oiplen; u_char *data; uint16_t flags, proto, iplen; gre = (struct gre_hdr *) ((u_char *) oip + (oip->ip_hl << 2)); data = (u_char *) (gre + 1); if (end <= data) return (-1); /* We support only RFC 2784 */ flags = ntohs(gre->gre_flags); if ((flags & ~GRE_CHECKSUM) != 0) { syslog(LOG_DEBUG, "%s: dropping RFC 1701 encapsulation: flags = %x", __func__, flags); return (-1); } proto = ntohs(gre->gre_proto); if (proto != GRE_IP4PROTO) { syslog(LOG_DEBUG, "%s: dropping encapsulated packet: bad protocol %d", __func__, proto); return (-1); } if (!(flags & GRE_CHECKSUM)) data = GRE_NOCKSUM_DATA(gre); /* Check for the proper length of the packet */ ip = (struct ip_hdr *) data; if (data + sizeof(struct ip_hdr) > end) return (-1); iplen = ntohs(ip->ip_len); if (data + iplen > end) return (-1); if (flags & GRE_CHECKSUM) { u_int sum = gre->gre_sum, tmp; gre->gre_sum = 0; tmp = ip_cksum_add(gre, sizeof(struct gre_hdr) + iplen, 0); tmp = ip_cksum_carry(tmp); if (sum != tmp) { syslog(LOG_INFO, "%s: dropping encapsulated packet: bad checksum: %x vs %x", __func__, ntohs(sum), ntohs(tmp)); return (-1); } } *pip = ip; *piplen = iplen; return (0); }