mirror of
https://github.com/nmap/nmap.git
synced 2025-12-28 02:19:04 +00:00
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]
218 lines
4.4 KiB
C
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);
|
|
}
|