> First this looks hackish. For general purpose packet insertion
> you would probably use a SOCK_PACKET socket though (which operates
> at layer2 only), instead of doing all that special purpose code.
> You would inject it to a dummy interface.
Yes, the raw socket approach is crude. Since I am working from
ignorance, I am leaning heavily on published information such as
Steven's "Unix Network Programming" and Rubini's "Linux Device
Drivers". Steven's discusses raw sockets in great depth, but only for
ICMP and UDP.
SOCK_PACKET seems to be a Linux-ism and I have not found any description
of this socket type (the 'socket' man page just mentions its existance
and says nothing about how it acts). Where is there a description of
this mechanism?
Quote:> Linux 2.2 also has a special purpose device for this application: > ethertap.
Alas, I must stay with the 2.0.xx series. My code is part of a much
larger system and the company has fixed on 2.0.xx as the delivery
vehicle.
Quote:>> ICMP and UDP messages work fine. TCP messages fail, but in a rather
>> unusual way. It appears that the raw socket passes the IP and TCP
>> headers, but with the IP total length set as just the size of the
>> two headers without the data. But the incoming packet does have
>data.
> Does this happen on sending or receiving?
Sending data. According to Steven's, you can not have a raw socket for
reading TCP, only for writing.
Quote:> Could you post a small test program for that? (that would clear the
> ambiguities)
Here is the offending code. 'packet' is the incoming data packet with
a prepended Cisco header. (I have removed my debugging statements so
you can easily see the code).
void
relay_tcp_pkt (unsigned char *packet, int packet_length)
{
int on, result;
struct iphdr *ip;
struct tcphdr *tcp;
/* Strip off the cisco header. */
packet = packet + sizeof (struct cisco_hdr);
packet_length = packet_length - sizeof (struct cisco_hdr);
ip = (struct iphdr *) packet;
tcp = (struct tcphdr *) (packet + (ip->ihl * 4));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = tcp->dest;
sockaddr.sin_addr.s_addr = ip->daddr;
if (TCP_sock == 0) {
TCP_sock = socket (AF_INET, SOCK_RAW, IPPROTO_TCP);
if (TCP_sock < 0) {
if (errno == EPERM)
printf ("Must run as root\n");
else
perror ("Opening TCP socket");
exit (-1);
}
on = 1;
if (setsockopt (TCP_sock, IPPROTO_IP, IP_HDRINCL,
&on, sizeof (on)) < 0) {
perror ("Setting TCP socket options");
exit (-1);
}
}
result = sendto (TCP_sock, packet, packet_length, 0,
&sockaddr, sizeof (struct sockaddr));
if (result < 0) {
perror ("Error relaying TCP packet");
}
Quote:}
With a de*, I can see the packet is correctly formed upto the
'sendto' and the packet_length is correct. When I look at the packet
comming back through my device driver, I see the mysteriously shortened
packet with no data, but properly formed IP and TCP headers.
Quote:> Does 2.2 show the same thing?
I will try building a 2.2.xx kernel and see what happens. I also have
access to a Sun system to see how it's raw sockets behave.
Dave Koogler