mirror of
https://github.com/nmap/nmap.git
synced 2026-01-05 14:09:02 +00:00
133 lines
2.9 KiB
C
133 lines
2.9 KiB
C
/*
|
|
* ip6.c
|
|
*
|
|
* Copyright (c) 2002 Dug Song <dugsong@monkey.org>
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
#include "dnet_winconfig.h"
|
|
#else
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "dnet.h"
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#define IP6_IS_EXT(n) \
|
|
((n) == IP_PROTO_HOPOPTS || (n) == IP_PROTO_DSTOPTS || \
|
|
(n) == IP_PROTO_ROUTING || (n) == IP_PROTO_FRAGMENT)
|
|
|
|
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 + 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 + 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 + 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
ssize_t
|
|
ip6_add_option(void *buf, size_t len, int proto,
|
|
const void *optbuf, size_t optlen)
|
|
{
|
|
struct ip6_hdr *ip6;
|
|
struct tcp_hdr *tcp = NULL;
|
|
u_char *p;
|
|
int hl, datalen, padlen;
|
|
|
|
if (proto != IP_PROTO_TCP) {
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
|
|
ip6 = (struct ip6_hdr *)buf;
|
|
p = (u_char *)buf + IP6_HDR_LEN;
|
|
|
|
tcp = (struct tcp_hdr *)p;
|
|
hl = tcp->th_off << 2;
|
|
p = (u_char *)tcp + hl;
|
|
|
|
datalen = ntohs(ip6->ip6_plen) + IP6_HDR_LEN - (p - (u_char *)buf);
|
|
|
|
/* Compute padding to next word boundary. */
|
|
if ((padlen = 4 - (optlen % 4)) == 4)
|
|
padlen = 0;
|
|
|
|
/* XXX - IP_HDR_LEN_MAX == TCP_HDR_LEN_MAX */
|
|
if (hl + optlen + padlen > IP_HDR_LEN_MAX ||
|
|
ntohs(ip6->ip6_plen) + IP6_HDR_LEN + optlen + padlen > len) {
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
|
|
/* Shift any existing data. */
|
|
if (datalen) {
|
|
memmove(p + optlen + padlen, p, datalen);
|
|
}
|
|
/* XXX - IP_OPT_NOP == TCP_OPT_NOP */
|
|
if (padlen) {
|
|
memset(p, IP_OPT_NOP, padlen);
|
|
p += padlen;
|
|
}
|
|
memmove(p, optbuf, optlen);
|
|
p += optlen;
|
|
optlen += padlen;
|
|
|
|
tcp->th_off = (p - (u_char *)tcp) >> 2;
|
|
|
|
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) + optlen);
|
|
|
|
return (optlen);
|
|
}
|