Discussion:
Code working with LIBNET_RAW4, not with LIBNET_LINK
Karen Pease
2005-01-31 04:27:55 UTC
Permalink
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work computer) (I
discovered this shortly after I send my last emaiL); I've tried to work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.

The main problem is mac addrs. The libnet example code for raw sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I mentioned
before, this means that the code is effectively worthless in real-world
applications, since you don't know beforehand what a target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to home, I
need to be able to look up the router's mac addr (in fact, if I hard code it,
they make it home just fine). I previously asked if there was a libnet
function to do this for you. I got no clear response, so I assume the answer
is "no".

So as not to bother the list any more, I decided to try and look it up myself;
to the best of my knowlege, this is done with arp who-has requests. So, I
tried sending who-has requests, and set up this nice system to send them out
and sniff the results back off the network. I got no response. Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see in
sniffed network traffic. All of the who-has requests seemed to be structured
the same (including mine). So, I'm not sure what I'm missing.

In short, I have to ask: How can I get a remote machine's mac addr to use with
libnet? I'm getting somewhat frustrated here. :(

- Karen
Mike Schiffman
2005-01-31 06:31:28 UTC
Permalink
I mentioned this in last email. You need to use libdnet's route lookup
and ARP cache query routines. Firewalk does exactly this. Below is the
relevant function from Firewalk-5.0/src/packet_build.c.

int
fw_packet_build_probe(struct firepack **fp)
{
arp_t *a;
route_t *r;
struct arp_entry arp;
struct route_entry route;

/* first build our transport layer header */
switch ((*fp)->protocol)
{
case IPPROTO_UDP:
if (fw_packet_build_udp(fp) == -1)
{
/* error msg set in fw_packet_build_udp() */
return (-1);
}
break;
case IPPROTO_TCP:
if (fw_packet_build_tcp(fp) == -1)
{
/* error msg set in fw_packet_build_tcp() */
return (-1);
}
break;
default:
sprintf((*fp)->errbuf,
"fw_packet_build_probe(): unknown protocol");
return (-1);
}

/* build our IPv4 header */
(*fp)->ip = libnet_build_ipv4(
(*fp)->packet_size, /* packetlength */
0, /* IP tos */
(*fp)->id, /* IP id */
0, /* IP frag bits */
(*fp)->ttl, /* IP time to live */
(*fp)->protocol, /* transport protocol */
0, /* checksum */
(*fp)->sin.sin_addr.s_addr, /* IP source */
(*fp)->metric, /* IP destination */
NULL, /* IP payload */
0, /* IP payload size */
(*fp)->l, /* libnet context */
0); /* No saved ptag */

if ((*fp)->ip == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "libnet_build_ipv4()
%s",
libnet_geterror((*fp)->l));
return (-1);
}

/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();
if (r == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_open()");
route_close(r);
return (-1);
}

/* convert the metric address to dnet's native addr_t format */
if (addr_aton(libnet_addr2name4((*fp)->metric, 0),
&route.route_dst) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "addr_aton()");
route_close(r);
return (-1);
}
/* get the route entry telling us how to reach the metric */
if (route_get(r, &route) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
route_close(r);
return (-1);
}
route_close(r);

a = arp_open();
if (a == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "arp_open()");
return (-1);
}
/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
if (arp_get(a, &arp) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
arp_close(a);
return (-1);
}
arp_close(a);

/* build our ethernet header */
if (libnet_autobuild_ethernet(
(u_char *)&arp.arp_ha.addr_eth,
ETHERTYPE_IP,
(*fp)->l) == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE,
"libnet_autobuild_ethernet() %s",
libnet_geterror((*fp)->l));
arp_close(a);
return (-1);
}

return (1);
}
Post by Karen Pease
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work computer) (I
discovered this shortly after I send my last emaiL); I've tried to work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.
The main problem is mac addrs. The libnet example code for raw sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I mentioned
before, this means that the code is effectively worthless in real-world
applications, since you don't know beforehand what a target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to home, I
need to be able to look up the router's mac addr (in fact, if I hard code it,
they make it home just fine). I previously asked if there was a libnet
function to do this for you. I got no clear response, so I assume the answer
is "no".
So as not to bother the list any more, I decided to try and look it up myself;
to the best of my knowlege, this is done with arp who-has requests.
So, I
tried sending who-has requests, and set up this nice system to send them out
and sniff the results back off the network. I got no response.
Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see in
sniffed network traffic. All of the who-has requests seemed to be structured
the same (including mine). So, I'm not sure what I'm missing.
In short, I have to ask: How can I get a remote machine's mac addr to use with
libnet? I'm getting somewhat frustrated here. :(
- Karen
--
Mike Schiffman, CISSP
http://www.packetfactory.net/schiffman
Doveryay No Proveryay
Karen Pease
2005-02-01 06:34:46 UTC
Permalink
Just as the libnet code examples only work for hard-coded mac addrs, this code
only works for the gateway. For example, lets try to generalize it (I'll cut
out my actual target ip; it's non-local):

struct arp_entry arp;
#if 1
int ret=addr_pton("192.168.0.1",&(arp.arp_pa)); //My gateway
#else
int ret=addr_pton("AAA.BBB.CCC.DDD",&(arp.arp_pa)); //IP snipped out
#endif
printf("IP: %d.%d.%d.%d (%d)\n",((u_int8_t*)(&arp.arp_pa.addr_eth))
[0],((u_int8_t*)(&arp.arp_pa.addr_eth))[1],((u_int8_t*)
(&arp.arp_pa.addr_eth))[2],((u_int8_t*)(&arp.arp_pa.addr_eth))[3],ret);

arp_t* a=arp_open();
printf("arp_t: %d\n",a);

ret=arp_get(a,&arp);
printf("%d\n",ret);

arp_close(a);

for (int i=0; i<6; i++)
uc.dest_mac[i]=((u_int8_t*)(&arp.arp_ha.addr_eth))[i];

printf("saddr: %02x.%02x.%02x.%02x.%02x.%02x daddr: %02x.%02x.%02x.
%02x.%02x.
%02x\n",uc.src_mac[0],uc.src_mac[1],uc.src_mac[2],uc.src_mac[3],uc.src_mac[4],uc.src_mac[5],uc.dest_mac[0],uc.dest_mac[1],uc.dest_mac[2],uc.dest_mac[3],uc.dest_mac[4],uc.dest_mac[5]);
send(&uc,argv[3]);

If we run this code as-is, we get:

IP: 192.168.0.1 (0)
arp_t: 134564104
0
saddr: 00.50.04.6c.e7.30 daddr: 00.20.e0.35.54.40

However, if we change the #if 1 to a #if 0, we get:

IP: AAA.BBB.CCC.DDD (0)
arp_t: 134564104
-1
saddr: 00.50.04.6c.e7.30 daddr: 00.00.00.00.00.00

As you'll note, arp_get gives an error (by returning -1) and doesn't set the
hardware address.

- Karen
Post by Mike Schiffman
I mentioned this in last email. You need to use libdnet's route lookup
and ARP cache query routines. Firewalk does exactly this. Below is the
relevant function from Firewalk-5.0/src/packet_build.c.
int
fw_packet_build_probe(struct firepack **fp)
{
arp_t *a;
route_t *r;
struct arp_entry arp;
struct route_entry route;
/* first build our transport layer header */
switch ((*fp)->protocol)
{
if (fw_packet_build_udp(fp) == -1)
{
/* error msg set in fw_packet_build_udp() */
return (-1);
}
break;
if (fw_packet_build_tcp(fp) == -1)
{
/* error msg set in fw_packet_build_tcp() */
return (-1);
}
break;
sprintf((*fp)->errbuf,
"fw_packet_build_probe(): unknown protocol");
return (-1);
}
/* build our IPv4 header */
(*fp)->ip = libnet_build_ipv4(
(*fp)->packet_size, /* packetlength */
0, /* IP tos */
(*fp)->id, /* IP id */
0, /* IP frag bits */
(*fp)->ttl, /* IP time to live */
(*fp)->protocol, /* transport protocol */
0, /* checksum */
(*fp)->sin.sin_addr.s_addr, /* IP source */
(*fp)->metric, /* IP destination */
NULL, /* IP payload */
0, /* IP payload size */
(*fp)->l, /* libnet context */
0); /* No saved ptag */
if ((*fp)->ip == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "libnet_build_ipv4()
%s",
libnet_geterror((*fp)->l));
return (-1);
}
/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();
if (r == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_open()");
route_close(r);
return (-1);
}
/* convert the metric address to dnet's native addr_t format */
if (addr_aton(libnet_addr2name4((*fp)->metric, 0),
&route.route_dst) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "addr_aton()");
route_close(r);
return (-1);
}
/* get the route entry telling us how to reach the metric */
if (route_get(r, &route) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
route_close(r);
return (-1);
}
route_close(r);
a = arp_open();
if (a == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "arp_open()");
return (-1);
}
/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
if (arp_get(a, &arp) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
arp_close(a);
return (-1);
}
arp_close(a);
/* build our ethernet header */
if (libnet_autobuild_ethernet(
(u_char *)&arp.arp_ha.addr_eth,
ETHERTYPE_IP,
(*fp)->l) == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE,
"libnet_autobuild_ethernet() %s",
libnet_geterror((*fp)->l));
arp_close(a);
return (-1);
}
return (1);
}
Post by Karen Pease
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work computer) (I
discovered this shortly after I send my last emaiL); I've tried to work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.
The main problem is mac addrs. The libnet example code for raw sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I mentioned
before, this means that the code is effectively worthless in real-world
applications, since you don't know beforehand what a target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to home, I
need to be able to look up the router's mac addr (in fact, if I hard code it,
they make it home just fine). I previously asked if there was a libnet
function to do this for you. I got no clear response, so I assume the answer
is "no".
So as not to bother the list any more, I decided to try and look it up myself;
to the best of my knowlege, this is done with arp who-has requests.
So, I
tried sending who-has requests, and set up this nice system to send them out
and sniff the results back off the network. I got no response.
Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see in
sniffed network traffic. All of the who-has requests seemed to be structured
the same (including mine). So, I'm not sure what I'm missing.
In short, I have to ask: How can I get a remote machine's mac addr to use with
libnet? I'm getting somewhat frustrated here. :(
- Karen
--
Mike Schiffman, CISSP
http://www.packetfactory.net/schiffman
Doveryay No Proveryay
Manu Garg
2005-02-01 08:05:46 UTC
Permalink
Karen,

Let me first try to understand your problem. You have an arrangement like this:
A (local/home m/c) ---->Internet----->B(work m/c)
You are trying to send a packet to B with LIBNET_LINK interface, but
you are not able to build the ethernet header of the packet, because
you don't have hardware address of B. Am I right? If yes, then read
on.

First thing: It's NOT possible for you to find out hw address of the
machine at the OTHER side of the router/gateway and it's NOT REQUIRED
also.

Hardware addresses matter only in your local domain and are important
only to ethernet. After that your router comes into picture which
works at layer 3 ie. IP layer. To make your packet reach machine B,
you need to first get it to your router and to do that you need your
router's hw address NOT machine B's. Your router reads the destination
IP address and forwards the packet to the correct route.

Code pointed by Mike does exactly that. The code first reads the
kernel's routing table to find out the proper route for the
destination and then it finds out hw address of that router(gateway)
by arp cache lookup. That's what you need.

If it still doesn't make any sense, I'd suggest you to read a bit on
routing and link layer protocols (of course, only if I am getting your
problem right :-))

Cheers,
Manu



On Tue, 1 Feb 2005 00:34:46 -0600, Karen Pease
Post by Karen Pease
Just as the libnet code examples only work for hard-coded mac addrs, this code
only works for the gateway. For example, lets try to generalize it (I'll cut
struct arp_entry arp;
#if 1
int ret=addr_pton("192.168.0.1",&(arp.arp_pa)); //My gateway
#else
int ret=addr_pton("AAA.BBB.CCC.DDD",&(arp.arp_pa)); //IP snipped out
#endif
printf("IP: %d.%d.%d.%d (%d)\n",((u_int8_t*)(&arp.arp_pa.addr_eth))
[0],((u_int8_t*)(&arp.arp_pa.addr_eth))[1],((u_int8_t*)
(&arp.arp_pa.addr_eth))[2],((u_int8_t*)(&arp.arp_pa.addr_eth))[3],ret);
arp_t* a=arp_open();
printf("arp_t: %d\n",a);
ret=arp_get(a,&arp);
printf("%d\n",ret);
arp_close(a);
for (int i=0; i<6; i++)
uc.dest_mac[i]=((u_int8_t*)(&arp.arp_ha.addr_eth))[i];
printf("saddr: %02x.%02x.%02x.%02x.%02x.%02x daddr: %02x.%02x.%02x.
%02x.%02x.
%02x\n",uc.src_mac[0],uc.src_mac[1],uc.src_mac[2],uc.src_mac[3],uc.src_mac[4],uc.src_mac[5],uc.dest_mac[0],uc.dest_mac[1],uc.dest_mac[2],uc.dest_mac[3],uc.dest_mac[4],uc.dest_mac[5]);
send(&uc,argv[3]);
IP: 192.168.0.1 (0)
arp_t: 134564104
0
saddr: 00.50.04.6c.e7.30 daddr: 00.20.e0.35.54.40
IP: AAA.BBB.CCC.DDD (0)
arp_t: 134564104
-1
saddr: 00.50.04.6c.e7.30 daddr: 00.00.00.00.00.00
As you'll note, arp_get gives an error (by returning -1) and doesn't set the
hardware address.
- Karen
Post by Mike Schiffman
I mentioned this in last email. You need to use libdnet's route lookup
and ARP cache query routines. Firewalk does exactly this. Below is the
relevant function from Firewalk-5.0/src/packet_build.c.
int
fw_packet_build_probe(struct firepack **fp)
{
arp_t *a;
route_t *r;
struct arp_entry arp;
struct route_entry route;
/* first build our transport layer header */
switch ((*fp)->protocol)
{
if (fw_packet_build_udp(fp) == -1)
{
/* error msg set in fw_packet_build_udp() */
return (-1);
}
break;
if (fw_packet_build_tcp(fp) == -1)
{
/* error msg set in fw_packet_build_tcp() */
return (-1);
}
break;
sprintf((*fp)->errbuf,
"fw_packet_build_probe(): unknown protocol");
return (-1);
}
/* build our IPv4 header */
(*fp)->ip = libnet_build_ipv4(
(*fp)->packet_size, /* packetlength */
0, /* IP tos */
(*fp)->id, /* IP id */
0, /* IP frag bits */
(*fp)->ttl, /* IP time to live */
(*fp)->protocol, /* transport protocol */
0, /* checksum */
(*fp)->sin.sin_addr.s_addr, /* IP source */
(*fp)->metric, /* IP destination */
NULL, /* IP payload */
0, /* IP payload size */
(*fp)->l, /* libnet context */
0); /* No saved ptag */
if ((*fp)->ip == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "libnet_build_ipv4()
%s",
libnet_geterror((*fp)->l));
return (-1);
}
/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();
if (r == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_open()");
route_close(r);
return (-1);
}
/* convert the metric address to dnet's native addr_t format */
if (addr_aton(libnet_addr2name4((*fp)->metric, 0),
&route.route_dst) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "addr_aton()");
route_close(r);
return (-1);
}
/* get the route entry telling us how to reach the metric */
if (route_get(r, &route) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
route_close(r);
return (-1);
}
route_close(r);
a = arp_open();
if (a == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "arp_open()");
return (-1);
}
/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
if (arp_get(a, &arp) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
arp_close(a);
return (-1);
}
arp_close(a);
/* build our ethernet header */
if (libnet_autobuild_ethernet(
(u_char *)&arp.arp_ha.addr_eth,
ETHERTYPE_IP,
(*fp)->l) == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE,
"libnet_autobuild_ethernet() %s",
libnet_geterror((*fp)->l));
arp_close(a);
return (-1);
}
return (1);
}
Post by Karen Pease
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work computer) (I
discovered this shortly after I send my last emaiL); I've tried to work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.
The main problem is mac addrs. The libnet example code for raw sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I mentioned
before, this means that the code is effectively worthless in real-world
applications, since you don't know beforehand what a target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to home, I
need to be able to look up the router's mac addr (in fact, if I hard code it,
they make it home just fine). I previously asked if there was a libnet
function to do this for you. I got no clear response, so I assume the answer
is "no".
So as not to bother the list any more, I decided to try and look it up myself;
to the best of my knowlege, this is done with arp who-has requests.
So, I
tried sending who-has requests, and set up this nice system to send them out
and sniff the results back off the network. I got no response.
Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see in
sniffed network traffic. All of the who-has requests seemed to be structured
the same (including mine). So, I'm not sure what I'm missing.
In short, I have to ask: How can I get a remote machine's mac addr to use with
libnet? I'm getting somewhat frustrated here. :(
- Karen
--
Mike Schiffman, CISSP
http://www.packetfactory.net/schiffman
Doveryay No Proveryay
--
Manu Garg
http://manugarg.freezope.org
"Wake Up! Free Thyself."
Karen Pease
2005-02-01 21:55:49 UTC
Permalink
Post by Manu Garg
Karen,
Let me first try to understand your problem. You have an arrangement like
this: A (local/home m/c) ---->Internet----->B(work m/c)
A (local/home m/c) ----> router (NAT, with port forwarding) ----> Internet
----> B (work m/c)
Post by Manu Garg
First thing: It's NOT possible for you to find out hw address of the
machine at the OTHER side of the router/gateway and it's NOT REQUIRED
also.
I already understood that :) I still need to be able to get the gateway's
MAC, however, and this is causing problems.
Post by Manu Garg
To make your packet reach machine B,
you need to first get it to your router and to do that you need your
router's hw address NOT machine B's.
Yes; unfortunately, I have been unable to get its hw addr. When sending to my
work machine, I can use FF.FF.FF.FF.FF.FF and the packets will get there.
The same does not hold true in reverse, however.
Post by Manu Garg
Code pointed by Mike does exactly that. The code first reads the
kernel's routing table to find out the proper route for the
destination and then it finds out hw address of that router(gateway)
by arp cache lookup. That's what you need.
As I demonstrated in the previous email, the code provided by Mike fails on
looking up arbitrary addresses; it only works for the gateway. In my
example, I ran it at home and attempted to look up my gateway (192.168.0.1);
that succeeded. Then I ran it at home and attempted to look up my work
computer; it failed. The output was included in the previous email.

Thanks for your help, Manu.

- Karen
Post by Manu Garg
On Tue, 1 Feb 2005 00:34:46 -0600, Karen Pease
Post by Karen Pease
Just as the libnet code examples only work for hard-coded mac addrs, this
code only works for the gateway. For example, lets try to generalize it
struct arp_entry arp;
#if 1
int ret=addr_pton("192.168.0.1",&(arp.arp_pa)); //My gateway
#else
int ret=addr_pton("AAA.BBB.CCC.DDD",&(arp.arp_pa)); //IP snipped
out #endif
printf("IP: %d.%d.%d.%d
(%d)\n",((u_int8_t*)(&arp.arp_pa.addr_eth))
[0],((u_int8_t*)(&arp.arp_pa.addr_eth))[1],((u_int8_t*)
(&arp.arp_pa.addr_eth))[2],((u_int8_t*)(&arp.arp_pa.addr_eth))[3],ret);
arp_t* a=arp_open();
printf("arp_t: %d\n",a);
ret=arp_get(a,&arp);
printf("%d\n",ret);
arp_close(a);
for (int i=0; i<6; i++)
uc.dest_mac[i]=((u_int8_t*)(&arp.arp_ha.addr_eth))[i];
%02x.%02x.%02x. %02x.%02x.
%02x\n",uc.src_mac[0],uc.src_mac[1],uc.src_mac[2],uc.src_mac[3],uc.src_ma
c[4],uc.src_mac[5],uc.dest_mac[0],uc.dest_mac[1],uc.dest_mac[2],uc.dest_ma
c[3],uc.dest_mac[4],uc.dest_mac[5]); send(&uc,argv[3]);
IP: 192.168.0.1 (0)
arp_t: 134564104
0
saddr: 00.50.04.6c.e7.30 daddr: 00.20.e0.35.54.40
IP: AAA.BBB.CCC.DDD (0)
arp_t: 134564104
-1
saddr: 00.50.04.6c.e7.30 daddr: 00.00.00.00.00.00
As you'll note, arp_get gives an error (by returning -1) and doesn't set
the hardware address.
- Karen
Post by Mike Schiffman
I mentioned this in last email. You need to use libdnet's route lookup
and ARP cache query routines. Firewalk does exactly this. Below is the
relevant function from Firewalk-5.0/src/packet_build.c.
int
fw_packet_build_probe(struct firepack **fp)
{
arp_t *a;
route_t *r;
struct arp_entry arp;
struct route_entry route;
/* first build our transport layer header */
switch ((*fp)->protocol)
{
if (fw_packet_build_udp(fp) == -1)
{
/* error msg set in fw_packet_build_udp() */
return (-1);
}
break;
if (fw_packet_build_tcp(fp) == -1)
{
/* error msg set in fw_packet_build_tcp() */
return (-1);
}
break;
sprintf((*fp)->errbuf,
"fw_packet_build_probe(): unknown protocol");
return (-1);
}
/* build our IPv4 header */
(*fp)->ip = libnet_build_ipv4(
(*fp)->packet_size, /* packetlength */
0, /* IP tos */
(*fp)->id, /* IP id */
0, /* IP frag bits */
(*fp)->ttl, /* IP time to live */
(*fp)->protocol, /* transport protocol
*/ 0, /* checksum */
(*fp)->sin.sin_addr.s_addr, /* IP source */ (*fp)->metric,
/* IP destination */ NULL,
/* IP payload */ 0, /* IP payload
size */ (*fp)->l, /* libnet context */ 0);
/* No saved ptag */
if ((*fp)->ip == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "libnet_build_ipv4()
%s",
libnet_geterror((*fp)->l));
return (-1);
}
/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();
if (r == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_open()");
route_close(r);
return (-1);
}
/* convert the metric address to dnet's native addr_t format */
if (addr_aton(libnet_addr2name4((*fp)->metric, 0),
&route.route_dst) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "addr_aton()");
route_close(r);
return (-1);
}
/* get the route entry telling us how to reach the metric */
if (route_get(r, &route) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
route_close(r);
return (-1);
}
route_close(r);
a = arp_open();
if (a == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "arp_open()");
return (-1);
}
/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
if (arp_get(a, &arp) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
arp_close(a);
return (-1);
}
arp_close(a);
/* build our ethernet header */
if (libnet_autobuild_ethernet(
(u_char *)&arp.arp_ha.addr_eth,
ETHERTYPE_IP,
(*fp)->l) == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE,
"libnet_autobuild_ethernet() %s",
libnet_geterror((*fp)->l));
arp_close(a);
return (-1);
}
return (1);
}
Post by Karen Pease
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work computer) (I
discovered this shortly after I send my last emaiL); I've tried to work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.
The main problem is mac addrs. The libnet example code for raw sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I mentioned
before, this means that the code is effectively worthless in
real-world applications, since you don't know beforehand what a
target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to home, I
need to be able to look up the router's mac addr (in fact, if I hard code it,
they make it home just fine). I previously asked if there was a
libnet function to do this for you. I got no clear response, so I
assume the answer
is "no".
So as not to bother the list any more, I decided to try and look it up myself;
to the best of my knowlege, this is done with arp who-has requests.
So, I
tried sending who-has requests, and set up this nice system to send them out
and sniff the results back off the network. I got no response.
Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see
in sniffed network traffic. All of the who-has requests seemed to be
structured
the same (including mine). So, I'm not sure what I'm missing.
In short, I have to ask: How can I get a remote machine's mac addr to use with
libnet? I'm getting somewhat frustrated here. :(
- Karen
--
Mike Schiffman, CISSP
http://www.packetfactory.net/schiffman
Doveryay No Proveryay
Manu Garg
2005-02-02 01:16:36 UTC
Permalink
On Tue, 1 Feb 2005 15:55:49 -0600, Karen Pease
Post by Karen Pease
Post by Manu Garg
Karen,
Let me first try to understand your problem. You have an arrangement like
this: A (local/home m/c) ---->Internet----->B(work m/c)
A (local/home m/c) ----> router (NAT, with port forwarding) ----> Internet
----> B (work m/c)
Post by Manu Garg
First thing: It's NOT possible for you to find out hw address of the
machine at the OTHER side of the router/gateway and it's NOT REQUIRED
also.
I already understood that :) I still need to be able to get the gateway's
MAC, however, and this is causing problems.
Post by Manu Garg
To make your packet reach machine B,
you need to first get it to your router and to do that you need your
router's hw address NOT machine B's.
Yes; unfortunately, I have been unable to get its hw addr. When sending to my
work machine, I can use FF.FF.FF.FF.FF.FF and the packets will get there.
The same does not hold true in reverse, however.
Using FF.FF.FF.FF.FF.FF is not advisable as it's a broadcast address.
A packet sent with this hw address will be picked up by all the
machine in the local domain including your router. It's not working in
reverse direction because of some other reason like probably your
router at work doesn't forward broadcast packet.
Post by Karen Pease
Post by Manu Garg
Code pointed by Mike does exactly that. The code first reads the
kernel's routing table to find out the proper route for the
destination and then it finds out hw address of that router(gateway)
by arp cache lookup. That's what you need.
As I demonstrated in the previous email, the code provided by Mike fails on
looking up arbitrary addresses; it only works for the gateway. In my
example, I ran it at home and attempted to look up my gateway (192.168.0.1);
that succeeded. Then I ran it at home and attempted to look up my work
computer; it failed. The output was included in the previous email.
In your example code, you are trying to find out the hw address of
machine B, which is not possible. What you need to do is to find out
router from the ROUTING TABLE using route_get(r, &route) and then
router's hw using arp_get(a, &arp). Go through the following part of
the code once again (all error checks removed):

/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();

/* convert the metric address to dnet's native addr_t format */
/* (*fp)->metric is the destination ip address (IP ADDRESS OF MACHINE B)
addr_aton(libnet_addr2name4((*fp)->metric, 0), &route.route_dst) < 0)

/* get the route entry telling us how to reach the metric */
route_get(r, &route)
route_close(r);

a = arp_open();

/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
arp_get(a, &arp)
arp_close(a);
Post by Karen Pease
Thanks for your help, Manu.
You're welcome!!
Post by Karen Pease
- Karen
Post by Manu Garg
On Tue, 1 Feb 2005 00:34:46 -0600, Karen Pease
Post by Karen Pease
Just as the libnet code examples only work for hard-coded mac addrs, this
code only works for the gateway. For example, lets try to generalize it
struct arp_entry arp;
#if 1
int ret=addr_pton("192.168.0.1",&(arp.arp_pa)); //My gateway
#else
int ret=addr_pton("AAA.BBB.CCC.DDD",&(arp.arp_pa)); //IP snipped
out #endif
printf("IP: %d.%d.%d.%d
(%d)\n",((u_int8_t*)(&arp.arp_pa.addr_eth))
[0],((u_int8_t*)(&arp.arp_pa.addr_eth))[1],((u_int8_t*)
(&arp.arp_pa.addr_eth))[2],((u_int8_t*)(&arp.arp_pa.addr_eth))[3],ret);
arp_t* a=arp_open();
printf("arp_t: %d\n",a);
ret=arp_get(a,&arp);
printf("%d\n",ret);
arp_close(a);
for (int i=0; i<6; i++)
uc.dest_mac[i]=((u_int8_t*)(&arp.arp_ha.addr_eth))[i];
%02x.%02x.%02x. %02x.%02x.
%02x\n",uc.src_mac[0],uc.src_mac[1],uc.src_mac[2],uc.src_mac[3],uc.src_ma
c[4],uc.src_mac[5],uc.dest_mac[0],uc.dest_mac[1],uc.dest_mac[2],uc.dest_ma
c[3],uc.dest_mac[4],uc.dest_mac[5]); send(&uc,argv[3]);
IP: 192.168.0.1 (0)
arp_t: 134564104
0
saddr: 00.50.04.6c.e7.30 daddr: 00.20.e0.35.54.40
IP: AAA.BBB.CCC.DDD (0)
arp_t: 134564104
-1
saddr: 00.50.04.6c.e7.30 daddr: 00.00.00.00.00.00
As you'll note, arp_get gives an error (by returning -1) and doesn't set
the hardware address.
- Karen
Post by Mike Schiffman
I mentioned this in last email. You need to use libdnet's route lookup
and ARP cache query routines. Firewalk does exactly this. Below is the
relevant function from Firewalk-5.0/src/packet_build.c.
int
fw_packet_build_probe(struct firepack **fp)
{
arp_t *a;
route_t *r;
struct arp_entry arp;
struct route_entry route;
/* first build our transport layer header */
switch ((*fp)->protocol)
{
if (fw_packet_build_udp(fp) == -1)
{
/* error msg set in fw_packet_build_udp() */
return (-1);
}
break;
if (fw_packet_build_tcp(fp) == -1)
{
/* error msg set in fw_packet_build_tcp() */
return (-1);
}
break;
sprintf((*fp)->errbuf,
"fw_packet_build_probe(): unknown protocol");
return (-1);
}
/* build our IPv4 header */
(*fp)->ip = libnet_build_ipv4(
(*fp)->packet_size, /* packetlength */
0, /* IP tos */
(*fp)->id, /* IP id */
0, /* IP frag bits */
(*fp)->ttl, /* IP time to live */
(*fp)->protocol, /* transport protocol
*/ 0, /* checksum */
(*fp)->sin.sin_addr.s_addr, /* IP source */ (*fp)->metric,
/* IP destination */ NULL,
/* IP payload */ 0, /* IP payload
size */ (*fp)->l, /* libnet context */ 0);
/* No saved ptag */
if ((*fp)->ip == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "libnet_build_ipv4()
%s",
libnet_geterror((*fp)->l));
return (-1);
}
/*
* Now we need to get the MAC address of our first hop gateway.
* Dnet to the rescue! We start by doing a route table lookup
* to determine the IP address we use to get to the
* destination host (the metric).
*/
r = route_open();
if (r == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_open()");
route_close(r);
return (-1);
}
/* convert the metric address to dnet's native addr_t format */
if (addr_aton(libnet_addr2name4((*fp)->metric, 0),
&route.route_dst) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "addr_aton()");
route_close(r);
return (-1);
}
/* get the route entry telling us how to reach the metric */
if (route_get(r, &route) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
route_close(r);
return (-1);
}
route_close(r);
a = arp_open();
if (a == NULL)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "arp_open()");
return (-1);
}
/* get the MAC of the first hop gateway */
arp.arp_pa = route.route_gw;
if (arp_get(a, &arp) < 0)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, "route_get()");
arp_close(a);
return (-1);
}
arp_close(a);
/* build our ethernet header */
if (libnet_autobuild_ethernet(
(u_char *)&arp.arp_ha.addr_eth,
ETHERTYPE_IP,
(*fp)->l) == -1)
{
snprintf((*fp)->errbuf, FW_ERRBUF_SIZE,
"libnet_autobuild_ethernet() %s",
libnet_geterror((*fp)->l));
arp_close(a);
return (-1);
}
return (1);
}
Post by Karen Pease
A couple weeks ago, I posted here with problems sending packets via
LIBNET_LINk when they worked with LIBNET_RAW4. Last I posted, I thought I
had resolved the problem by using the libnet_ethernet_autobuild function;
however, it turns out that it was only working in a situation that I
previously had working (sending from my home computer to my work
computer) (I
discovered this shortly after I send my last emaiL); I've tried to
work on it
on my own, but have had no success in getting packets to arrive the other
way. So, I'm still stuck where I was before.
The main problem is mac addrs. The libnet example code for raw
sockets (which
I was pointed to before) uses hard coded mac addrs; naturally, as I
mentioned
before, this means that the code is effectively worthless in
real-world applications, since you don't know beforehand what a
target machine's mac
addr will be. I can get packets from my home computer to my work computer
using mac addr ff.ff.ff.ff.ff.ff; however, the same does not work in
reverse.
Assumedly this has something to do with my router (I'm behind NAT with port
forwarding for the port being sent to). To send packets from work to
home, I
need to be able to look up the router's mac addr (in fact, if I hard
code it,
they make it home just fine). I previously asked if there was a
libnet function to do this for you. I got no clear response, so I
assume the answer
is "no".
So as not to bother the list any more, I decided to try and look it
up myself;
to the best of my knowlege, this is done with arp who-has requests.
So, I
tried sending who-has requests, and set up this nice system to send
them out
and sniff the results back off the network. I got no response.
Looking in
tcpdump, only a small percentage of all machines on the network that issued
who-has requests got them answered - at least, so far as I could see
in sniffed network traffic. All of the who-has requests seemed to be
structured
the same (including mine). So, I'm not sure what I'm missing.
In short, I have to ask: How can I get a remote machine's mac addr to
use with
libnet? I'm getting somewhat frustrated here. :(
- Karen
--
Mike Schiffman, CISSP
http://www.packetfactory.net/schiffman
Doveryay No Proveryay
--
Manu Garg
http://manugarg.freezope.org
"Wake Up! Free Thyself."
Loading...