1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-28 02:19:04 +00:00
Files
nmap/libdnet-stripped/src/ip-util.c
daniel 50830f7488 o Added initial SCTP port scanning support to Nmap. SCTP is
a layer 4 protocol used mostly for telephony related applications.
  This brings the following new features:
  o SCTP INIT chunk port scan (-sY): open ports return an INIT-ACK
    chunk, closed ones an ABORT chunk.  This is the SCTP equivalent
    of a TCP SYN stealth scan.
  o SCTP COOKIE-ECHO chunk port scan (-sZ): open ports are silent,
    closed ports return an ABORT chunk.
  o SCTP INIT chunk ping probes (-PY): host discovery using SCTP
    INIT chunk packets.
  o SCTP-specific IP protocol scan (-sO -p sctp).
  o SCTP-specific traceroute support (--traceroute).
  o The ability to use the deprecated Adler32 algorithm as specified
    in RFC 2960 instead of CRC32C from RFC 4960 (--adler32).
  o 42 well-known SCTP ports were added to the nmap-services file.
  Part of the work on SCTP support was kindly sponsored by
  Compass Security AG, Switzerland.  [Daniel Roethlisberger]
2009-06-03 23:15:45 +00:00

218 lines
4.4 KiB
C

/*
* ip-util.c
*
* Copyright (c) 2002 Dug Song <dugsong@monkey.org>
*
* $Id: ip-util.c 595 2005-02-17 02:55:56Z dugsong $
*/
#ifdef _WIN32
#include "dnet_winconfig.h"
#else
#include "config.h"
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "dnet.h"
#include "crc32ct.h"
/* CRC-32C (Castagnoli). Public domain. */
static unsigned long
_crc32c(unsigned char *buf, int len)
{
int i;
unsigned long crc32 = ~0L;
unsigned long result;
unsigned char byte0, byte1, byte2, byte3;
for (i = 0; i < len; i++) {
CRC32C(crc32, buf[i]);
}
result = ~crc32;
byte0 = result & 0xff;
byte1 = (result >> 8) & 0xff;
byte2 = (result >> 16) & 0xff;
byte3 = (result >> 24) & 0xff;
crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
return crc32;
}
ssize_t
ip_add_option(void *buf, size_t len, int proto,
const void *optbuf, size_t optlen)
{
struct ip_hdr *ip;
struct tcp_hdr *tcp = NULL;
u_char *p;
int hl, datalen, padlen;
if (proto != IP_PROTO_IP && proto != IP_PROTO_TCP) {
errno = EINVAL;
return (-1);
}
ip = (struct ip_hdr *)buf;
hl = ip->ip_hl << 2;
p = (u_char *)buf + hl;
if (proto == IP_PROTO_TCP) {
tcp = (struct tcp_hdr *)p;
hl = tcp->th_off << 2;
p = (u_char *)tcp + hl;
}
datalen = (int) (ntohs(ip->ip_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(ip->ip_len) + optlen + padlen > len) {
errno = EINVAL;
return (-1);
}
/* XXX - IP_OPT_TYPEONLY() == TCP_OPT_TYPEONLY */
if (IP_OPT_TYPEONLY(((struct ip_opt *)optbuf)->opt_type))
optlen = 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;
if (proto == IP_PROTO_IP)
ip->ip_hl = (int) ((p - (u_char *)ip) >> 2);
else if (proto == IP_PROTO_TCP)
tcp->th_off = (int) ((p - (u_char *)tcp) >> 2);
ip->ip_len = htons((u_short) (ntohs(ip->ip_len) + optlen));
return (ssize_t)(optlen);
}
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((u_short)(ip->ip_p + 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((u_short)(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 */
}
} else if (ip->ip_p == IP_PROTO_SCTP) {
struct sctp_hdr *sctp = (struct sctp_hdr *)((u_char *)ip + hl);
if (len >= SCTP_HDR_LEN) {
sctp->sh_sum = 0;
sctp->sh_sum = htonl(_crc32c((u_char *)sctp, len));
}
} 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
ip_cksum_add(const void *buf, size_t len, int cksum)
{
uint16_t *sp = (uint16_t *)buf;
int n, sn;
sn = (int) len / 2;
n = (sn + 15) / 16;
/* XXX - unroll loop using Duff's device. */
switch (sn % 16) {
case 0: do {
cksum += *sp++;
case 15:
cksum += *sp++;
case 14:
cksum += *sp++;
case 13:
cksum += *sp++;
case 12:
cksum += *sp++;
case 11:
cksum += *sp++;
case 10:
cksum += *sp++;
case 9:
cksum += *sp++;
case 8:
cksum += *sp++;
case 7:
cksum += *sp++;
case 6:
cksum += *sp++;
case 5:
cksum += *sp++;
case 4:
cksum += *sp++;
case 3:
cksum += *sp++;
case 2:
cksum += *sp++;
case 1:
cksum += *sp++;
} while (--n > 0);
}
if (len & 1)
cksum += htons(*(u_char *)sp << 8);
return (cksum);
}