Skip to content

Commit

Permalink
Add a sockaddr dst argument to send_ip function that use raw sockets.
Browse files Browse the repository at this point in the history
Heretofore we have always extracted teh destination address directly
from the packet contents. But the raw packet bytes do not contain enough
information in one case: IPv6 link-local addresses. For those we really
need the scope ID, and for that we must pass this information all the
way down.

Before this, I got "no route to host" on OS link-local addresses. I
think that it was working on Linux only on accident, by the OS picking a
default interface or something.
  • Loading branch information
david committed Sep 19, 2011
1 parent d91b131 commit f41753c
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 85 deletions.
62 changes: 24 additions & 38 deletions libnetutil/netutil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3398,24 +3398,20 @@ int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int


/* Send an IP packet over a raw socket. */
int send_ip_packet_sd(int sd, const u8 *packet, unsigned int packetlen) {
int send_ip_packet_sd(int sd, const struct sockaddr_in *dst,
const u8 *packet, unsigned int packetlen) {
struct sockaddr_in sock;
struct ip *ip = (struct ip *) packet;
struct tcp_hdr *tcp;
struct udp_hdr *udp;
int res;

assert(sd >= 0);
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
#if HAVE_SOCKADDR_SA_LEN
sock.sin_len = sizeof(sock);
#endif
sock = *dst;

/* It is bogus that I need the address and port info when sending a RAW IP
packet, but it doesn't seem to work w/o them */
if (packetlen >= 20) {
sock.sin_addr.s_addr = ip->ip_dst.s_addr;
if (ip->ip_p == IPPROTO_TCP
&& packetlen >= (unsigned int) ip->ip_hl * 4 + 20) {
tcp = (struct tcp_hdr *) ((u8 *) ip + ip->ip_hl * 4);
Expand Down Expand Up @@ -3455,12 +3451,13 @@ int send_ip_packet_sd(int sd, const u8 *packet, unsigned int packetlen) {
/* Sends the supplied pre-built IPv4 packet. The packet is sent through
* the raw socket "sd" if "eth" is NULL. Otherwise, it gets sent at raw
* ethernet level. */
int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth, const u8 *packet,
unsigned int packetlen) {
int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
const struct sockaddr_in *dst,
const u8 *packet, unsigned int packetlen) {
if(eth)
return send_ip_packet_eth(eth, packet, packetlen);
else
return send_ip_packet_sd(sd, packet, packetlen);
return send_ip_packet_sd(sd, dst, packet, packetlen);
}


Expand All @@ -3469,8 +3466,9 @@ int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth, const u8 *packet
* Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
* which gives us a right to cut TCP header after 8th byte
* (shouldn't we inflate the header to 60 bytes too?) */
int send_frag_ip_packet(int sd, const struct eth_nfo *eth, const u8 *packet,
unsigned int packetlen, u32 mtu) {
int send_frag_ip_packet(int sd, const struct eth_nfo *eth,
const struct sockaddr_in *dst,
const u8 *packet, unsigned int packetlen, u32 mtu) {
struct ip *ip = (struct ip *) packet;
int headerlen = ip->ip_hl * 4; // better than sizeof(struct ip)
u32 datalen = packetlen - headerlen;
Expand All @@ -3483,7 +3481,7 @@ int send_frag_ip_packet(int sd, const struct eth_nfo *eth, const u8 *packet,

if (datalen <= mtu) {
netutil_error("Warning: fragmentation (mtu=%lu) requested but the payload is too small already (%lu)", (unsigned long)mtu, (unsigned long)datalen);
return send_ip_packet_eth_or_sd(sd, eth, packet, packetlen);
return send_ip_packet_eth_or_sd(sd, eth, dst, packet, packetlen);
}

u8 *fpacket = (u8 *) safe_malloc(headerlen + mtu);
Expand All @@ -3504,7 +3502,7 @@ int send_frag_ip_packet(int sd, const struct eth_nfo *eth, const u8 *packet,
if (fragment > 1) // copy data payload
memcpy(fpacket + headerlen,
packet + headerlen + (fragment - 1) * mtu, fdatalen);
res = send_ip_packet_eth_or_sd(sd, eth, fpacket, ntohs(ip->ip_len));
res = send_ip_packet_eth_or_sd(sd, eth, dst, fpacket, ntohs(ip->ip_len));
if (res == -1)
break;
}
Expand Down Expand Up @@ -3558,29 +3556,20 @@ static int send_ipv6_eth(const struct eth_nfo *eth, const u8 *packet, unsigned i

/* Send an IPv6 packet over a raw socket, on platforms where IPPROTO_RAW implies
IP_HDRINCL-like behavior. */
static int send_ipv6_ipproto_raw(const unsigned char *packet, unsigned int packetlen) {
struct ip6_hdr *hdr;
struct sockaddr_in6 dest = { 0 };
static int send_ipv6_ipproto_raw(const struct sockaddr_in6 *dst,
const unsigned char *packet, unsigned int packetlen) {
int sd, n;

sd = -1;
n = -1;

if (packetlen < sizeof(*hdr))
return -1;

hdr = (struct ip6_hdr *) packet;
dest.sin6_family = AF_INET6;
memcpy(&dest.sin6_addr.s6_addr, &hdr->ip6_dst, sizeof(dest.sin6_addr.s6_addr));
dest.sin6_port = 0;

sd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
if (sd == -1) {
perror("socket");
goto bail;
}

n = Sendto(__func__, sd, packet, packetlen, 0, (struct sockaddr *) &dest, sizeof(dest));
n = Sendto(__func__, sd, packet, packetlen, 0, (struct sockaddr *) dst, sizeof(*dst));

bail:
if (sd != -1)
Expand Down Expand Up @@ -3669,9 +3658,9 @@ static const unsigned char *add_exthdr_ancillary(struct msghdr *msg,
with EPROTOTYPE because there are specialized functions to add these headers
using the IPv6 socket API. These do not offer as much control because they
are controlled by the OS, and may be reordered, for example. */
static int send_ipv6_ip(const unsigned char *packet, size_t packetlen) {
static int send_ipv6_ip(const struct sockaddr_in6 *dst,
const unsigned char *packet, size_t packetlen) {
struct msghdr msg;
struct sockaddr_in6 dest = { 0 };
struct iovec iov;

const unsigned char *end;
Expand All @@ -3685,9 +3674,9 @@ static int send_ipv6_ip(const unsigned char *packet, size_t packetlen) {
sd = -1;
n = -1;

/* Set up sendmsg data structure. dest and iov are filled in below. */
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
/* Set up sendmsg data structure. iov is filled in below. */
msg.msg_name = (void *) dst;
msg.msg_namelen = sizeof(*dst);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
Expand All @@ -3698,10 +3687,6 @@ static int send_ipv6_ip(const unsigned char *packet, size_t packetlen) {
return -1;
hdr = (struct ip6_hdr *) packet;

dest.sin6_family = AF_INET6;
memcpy(&dest.sin6_addr.s6_addr, &hdr->ip6_dst, sizeof(dest.sin6_addr.s6_addr));
dest.sin6_port = 0;

/* This can also be set with setsockopt(IPPROTO_IPV6, IPV6_TCLASS). */
#ifdef IPV6_TCLASS
tclass = ntohl(hdr->ip6_flow & IP6_FLOWINFO_MASK) >> 20;
Expand Down Expand Up @@ -3770,14 +3755,15 @@ static int send_ipv6_ip(const unsigned char *packet, size_t packetlen) {
#endif

/* For now, the sd argument is ignored. */
int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen) {
int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
const struct sockaddr_in6 *dst, const u8 *packet, unsigned int packetlen) {
if (eth != NULL) {
return send_ipv6_eth(eth, packet, packetlen);
} else {
#if HAVE_IPV6_IPPROTO_RAW
return send_ipv6_ipproto_raw(packet, packetlen);
return send_ipv6_ipproto_raw(dst, packet, packetlen);
#elif !WIN32
return send_ipv6_ip(packet, packetlen);
return send_ipv6_ip(dst, packet, packetlen);
#endif
}

Expand Down
13 changes: 8 additions & 5 deletions libnetutil/netutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,24 +435,27 @@ int route_dst(const struct sockaddr_storage * const dst, struct route_nfo *rnfo,
const char *device, const struct sockaddr_storage *spoofss);

/* Send an IP packet over a raw socket. */
int send_ip_packet_sd(int sd, const u8 *packet, unsigned int packetlen);
int send_ip_packet_sd(int sd, const struct sockaddr_in *dst, const u8 *packet, unsigned int packetlen);

/* Send an IP packet over an ethernet handle. */
int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen);

/* Sends the supplied pre-built IPv4 packet. The packet is sent through
* the raw socket "sd" if "eth" is NULL. Otherwise, it gets sent at raw
* ethernet level. */
int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen);
int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
const struct sockaddr_in *dst, const u8 *packet, unsigned int packetlen);

/* Sends an IPv4 packet. */
int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth, const u8 *packet, unsigned int len);
int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
const struct sockaddr_in6 *dst, const u8 *packet, unsigned int packetlen);

/* Create and send all fragments of a pre-built IPv4 packet.
* Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
* which gives us a right to cut TCP header after 8th byte */
int send_frag_ip_packet(int sd, const struct eth_nfo *eth, const u8 *packet,
unsigned int packetlen, u32 mtu);
int send_frag_ip_packet(int sd, const struct eth_nfo *eth,
const struct sockaddr_in *dst,
const u8 *packet, unsigned int packetlen, u32 mtu);

/* Wrapper for system function sendto(), which retries a few times when
* the call fails. It also prints informational messages about the
Expand Down
22 changes: 11 additions & 11 deletions nse_dnet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ static int ip_send (lua_State *L)
const char *packet = luaL_checkstring(L, 2);
char dev[16];
int ret;
struct sockaddr_storage srcss, dstss, *nexthop;
struct sockaddr_in *srcsin = (struct sockaddr_in *) &srcss;
struct sockaddr_in *dstsin = (struct sockaddr_in *) &dstss;
struct ip *ip = (struct ip *) packet;

if (udata->sock == -1)
return luaL_error(L, "raw socket not open to send");
Expand All @@ -228,21 +232,17 @@ static int ip_send (lua_State *L)

*dev = '\0';

/* build sockaddr for target from user packet and determine route */
memset(&dstss, 0, sizeof(dstss));
dstsin->sin_family = AF_INET;
dstsin->sin_addr.s_addr = ip->ip_dst.s_addr;

if (o.sendpref & PACKET_SEND_ETH)
{
struct route_nfo route;
struct sockaddr_storage srcss, dstss, *nexthop;
struct sockaddr_in *srcsin = (struct sockaddr_in *) &srcss;
struct sockaddr_in *dstsin = (struct sockaddr_in *) &dstss;
struct ip *ip = (struct ip *) packet;
u8 dstmac[6];
eth_nfo eth;

/* build sockaddr for target from user packet and determine route */
memset(&dstss, 0, sizeof(dstss));
dstsin->sin_family = AF_INET;
dstsin->sin_addr.s_addr = ip->ip_dst.s_addr;

if (!nmap_route_dst(&dstss, &route))
goto usesock;

Expand Down Expand Up @@ -283,14 +283,14 @@ static int ip_send (lua_State *L)

udata->eth = eth.ethsd = open_eth_cached(L, 1, route.ii.devname);

ret = send_ip_packet(udata->sock, &eth, (u8 *) packet, lua_objlen(L, 2));
ret = send_ip_packet(udata->sock, &eth, &dstss, (u8 *) packet, lua_objlen(L, 2));
} else {
usesock:
#ifdef WIN32
if (strlen(dev) > 0)
win32_fatal_raw_sockets(dev);
#endif
ret = send_ip_packet(udata->sock, NULL, (u8 *) packet, lua_objlen(L, 2));
ret = send_ip_packet(udata->sock, NULL, &dstss, (u8 *) packet, lua_objlen(L, 2));
}
if (ret == -1)
return safe_error(L, "error while sending: %s (errno %d)",
Expand Down
4 changes: 2 additions & 2 deletions osscan2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2121,7 +2121,7 @@ int HostOsScan::send_icmp_echo_probe(HostOsScanStats *hss,
o.ttl, get_random_u16(), tos, df, NULL, 0, seq, id,
ICMP_ECHO, pcode, NULL, datalen, &packetlen);
if(!packet) return -1;
res = send_ip_packet(rawsd, ethptr, packet, packetlen);
res = send_ip_packet(rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
if(res==-1) return -1;
}
Expand Down Expand Up @@ -2213,7 +2213,7 @@ int HostOsScan::send_closedudp_probe(HostOsScanStats *hss,
hss->upi.target.s_addr = ip->ip_dst.s_addr;
}

if ((res = send_ip_packet(rawsd, ethptr, packet, ntohs(ip->ip_len))) == -1)
if ((res = send_ip_packet(rawsd, ethptr, hss->target->TargetSockAddr(), packet, ntohs(ip->ip_len))) == -1)
{
gh_perror("send_ip_packet in %s", __func__);
return 1;
Expand Down
22 changes: 11 additions & 11 deletions scan_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3233,7 +3233,7 @@ static UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss,
&packetlen);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);

probe->tryno = tryno;
probe->pingseq = pingseq;
Expand Down Expand Up @@ -3442,7 +3442,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (hss->target->af() == AF_INET6) {
Expand All @@ -3462,7 +3462,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (pspec->type == PS_UDP) {
Expand All @@ -3484,7 +3484,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (hss->target->af() == AF_INET6) {
Expand All @@ -3502,7 +3502,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (pspec->type == PS_SCTP) {
Expand Down Expand Up @@ -3541,7 +3541,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (hss->target->af() == AF_INET6) {
Expand All @@ -3560,7 +3560,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
free(chunk);
Expand All @@ -3582,7 +3582,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (hss->target->af() == AF_INET6) {
Expand All @@ -3592,7 +3592,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (pspec->type == PS_ICMP) {
Expand All @@ -3608,7 +3608,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}
} else if (pspec->type == PS_ICMPV6) {
Expand All @@ -3627,7 +3627,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
}else assert(0); /* TODO: Maybe RPC scan and the like */

Expand Down
Loading

0 comments on commit f41753c

Please sign in to comment.