Currently it arp's and ping's and can send and receive UDP, which is fine for RTP based video and audio.
I wanted to setup some user space TCP/IP stack like Apline or LWIP and make a web server,
The MAC address is hard coded.
The network card in put promiscuous mode so DO NOT RUN THIS ON A HEAVILY LOADED SERVER.
It uses raw sockets so it must run as root.
It's only been tested on Linux.
/*****************************************************************************
* Copyright John Sokol (C) 2004
* You may use this code as long as you credit me and link to videotechnology.com
*****************************************************************************/#include
#include
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/ip.h>
// #include
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/if_packet.h>
#include <sys/ioctl.h>
// Evil Globals
/*our MAC address*/
unsigned char src_mac[6] = { 0x00, 0x0c, 0xf1, 0x75, 0xf8, 0xaa }; // Bogus
unsigned char src_ip[4] = { 192, 168, 0, 88 }; // Bogus
/*other host MAC address*/
unsigned char bcast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; //Broadcast
unsigned char dest_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; //Broadcast
unsigned char dest_ip[4] = { 255, 255, 255, 255 }; // Bogus
unsigned char arp_query_ip[4] = { 192, 168, 0, 16 }; // Bogus
u_int16_t
csum_partial (void *buffer, unsigned int len, u_int16_t prevsum)
{
u_int32_t sum = 0;
u_int16_t *ptr = buffer;
while (len > 1)
{
sum += *ptr++;
len -= 2;
}
if (len)
sokol@server:~$
sokol@server:~$
sokol@server:~$
sokol@server:~$ cat user-space-ip.c
#include
#include
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/ip.h>
// #include
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/if_packet.h>
#include <sys/ioctl.h>
// Evil Globals
/*our MAC address*/
unsigned char src_mac[6] = { 0x00, 0x0c, 0xf1, 0x75, 0xf8, 0xaa }; // Bogus
unsigned char src_ip[4] = { 192, 168, 0, 88 }; // Bogus
/*other host MAC address*/
unsigned char bcast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; //Broadcast
unsigned char dest_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; //Broadcast
unsigned char dest_ip[4] = { 255, 255, 255, 255 }; // Bogus
unsigned char arp_query_ip[4] = { 192, 168, 0, 16 }; // Bogus
u_int16_t
csum_partial (void *buffer, unsigned int len, u_int16_t prevsum)
{
u_int32_t sum = 0;
u_int16_t *ptr = buffer;
while (len > 1)
{
sum += *ptr++;
len -= 2;
}
if (len)
{
union
{
u_int8_t byte;
u_int16_t wyde;
} odd;
odd.wyde = 0;
odd.byte = *((u_int8_t *) ptr);
sum += odd.wyde;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += prevsum;
return (sum + (sum >> 16));
}
void
sendpack (int sock)
{
struct sockaddr_ll socket_address; /*target address */
void *buffer = (void *) malloc (ETH_FRAME_LEN); /*buffer for ethernet frame */
unsigned char *etherhead = buffer; /*pointer to ethenet header */
struct ethhdr *eh = (struct ethhdr *) etherhead; /*another pointer to ethernet header */
unsigned char *data = buffer + 14; /*userdata in ethernet frame */
int send_result = 0;
/*prepare sockaddr_ll*/
/*RAW communication*/
socket_address.sll_family = PF_PACKET;
/*we don't use a protocoll above ethernet layer ->just use anything here*/
socket_address.sll_protocol = htons (ETH_P_ALL);
/*index of the network device see full code later how to retrieve it*/
socket_address.sll_ifindex = if_nametoindex ("eth0");
printf ("if index for eth0 = %d\n", if_nametoindex ("eth0"));
/*ARP hardware identifier is ethernet*/
socket_address.sll_hatype = ARPHRD_ETHER; // for recv only
/*target is another host*/
socket_address.sll_pkttype = PACKET_BROADCAST; // for recv only
/*address length*/
socket_address.sll_halen = ETH_ALEN;
/*MAC - begin*/
socket_address.sll_addr[0] = 0x00;
socket_address.sll_addr[1] = 0x00;
socket_address.sll_addr[2] = 0x00;
socket_address.sll_addr[3] = 0x00;
socket_address.sll_addr[4] = 0x00;
socket_address.sll_addr[5] = 0x00;
/*MAC - end*/
socket_address.sll_addr[6] = 0x00; /*not used */
socket_address.sll_addr[7] = 0x00; /*not used */
memcpy ((void *) socket_address.sll_addr, (void *) dest_mac, ETH_ALEN);
/*set the frame header*/
memcpy ((void *) buffer, (void *) dest_mac, ETH_ALEN);
memcpy ((void *) (buffer + ETH_ALEN), (void *) src_mac, ETHALEN);
eh->h_proto = htons (ETH_P_ARP);
data[0] = 0;
data[1] = 1; // Hardware Type Ethernet
data[2] = 8;
data[3] = 0; // Protocol IP
data[4] = 6;
data[5] = 4; // Hardware size 6, protocol size 4
data[6] = 0;
data[7] = 1; // Opcode Request
memcpy ((void *) &data[8], (void *) src_mac, ETH_ALEN);
memcpy ((void *) &data[14], (void *) src_ip, 4);
memset ((void *) &data[18], 0, ETH_ALEN);
memcpy ((void *) &data[24], (void *) arp_query_ip, 4);
/*send the packet*/
send_result = sendto (sock, buffer, 61, 0,
(struct sockaddr *) &socket_address,
sizeof (socket_address));
if (send_result == -1)
{
printf ("error sending packet %d\n", errno);
if (errno == ENOTSOCK)
printf ("ENOTSOCK\n");
if (errno == EAGAIN)
printf ("EAGAIN\n");
if (errno == ENOBUFS)
printf ("ENOBUFS\n");
if (errno == EINVAL)
printf ("EINVAL\n");
if (errno == EPIPE)
printf ("EPIPE\n");
if (errno == EMSGSIZE)
printf ("EMSGSIZE\n");
if (errno == EBADF)
printf ("EBADF\n");
if (errno == EFAULT)
printf ("EFAULT\n");
}
}
void
recvpack (int sock)
{
char buffer[2048];
unsigned char *iphead, *ethhead;
char proto[10];
int n;
struct iphdr *ip;
struct icmphdr *icmp; //= (void *)((u_int32_t *)ip + ip.ihl );
struct tcphdr *tcp;
struct udphdr *udp;
n = recvfrom (sock, buffer, 2048, 0, NULL, NULL);
printf ("%d bytes read\n", n);
/* Check to see if the packet contains at least
* complete Ethernet (14), IP (20) and TCP/UDP
* (8) headers.
*/
if (n < 20)
{ // was 42
perror ("recvfrom():");
printf ("Incomplete packet (errno is %d)\n", errno);
close (sock);
exit (0);
}
ethhead = buffer;
if (!memcmp(ethhead, (void *) src_mac, 6) || !memcmp(ethhead, (void *) bcast_mac, 6) ) // IS it for our MAC?
{
printf ("Destination MAC address: "
"%02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[0], ethhead[1], ethhead[2],
ethhead[3], ethhead[4], ethhead[5]);
printf ("Source MAC address: "
"%02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[6], ethhead[7], ethhead[8],
ethhead[9], ethhead[10], ethhead[11]);
if (ethhead[12] == 0x08 && ethhead[13] == 0x00)
{
iphead = buffer + 14; /* Skip Ethernet header */
if (*iphead == 0x45) { /* Double check for IPv4 and no options present */
ip = (void *)iphead;
printf ("Source host %d.%d.%d.%d\n",
iphead[12], iphead[13], iphead[14], iphead[15]);
printf ("Dest host %d.%d.%d.%d\n",
iphead[16], iphead[17], iphead[18], iphead[19]);
printf ("Source,Dest ports %d,%d\n",
(iphead[20] << 8) + iphead[21],
(iphead[22] << 8) + iphead[23]);
sprintf (proto, "%d", iphead[9]);
if (iphead[9] == IPPROTO_ICMP) {
strcpy (proto, "ICMP");
icmp = (void *)iphead + 20;
if (icmp->type == ICMP_ECHO) {
fprintf(stderr, "PONG!\n");
u_int32_t tmp;
char tbuf[10];
/* Turn it around */
memcpy ( tbuf, (void *) (buffer + ETH_ALEN), ETH_ALEN);
memcpy ((void *) buffer, (void *) tbuf, ETH_ALEN);
memcpy ((void *) (buffer + ETH_ALEN), (void *) src_mac, ETH_ALEN);
//memcpy ((void *) tmp, (void *)&ip->saddr , 4);
tmp = ip->saddr;
ip->saddr = ip->daddr;
ip->daddr = tmp;
icmp->type = ICMP_ECHOREPLY;
icmp->checksum = 0;
icmp->checksum = ~csum_partial(icmp, ntohs(ip->tot_len) - ip->ihl*4, 0);
{
unsigned int i;
for (i = 44; i < ntohs(ip->tot_len); i++){
printf("%u:0x%02X ", i, ((unsigned char *)ip)[i]);
}
printf("\n");
int send_result;
struct sockaddr_ll socket_address; /*target address */
/*RAW communication*/
socket_address.sll_family = PF_PACKET;
/*we don't use a protocoll above ethernet layer ->just use anything here*/
socket_address.sll_protocol = htons (ETH_P_ALL);
/*index of the network device see full code later how to retrieve it*/
socket_address.sll_ifindex = if_nametoindex ("eth0");
printf ("if index for eth0 = %d\n", if_nametoindex ("eth0"));
/*ARP hardware identifier is ethernet*/
socket_address.sll_hatype = ARPHRD_ETHER; // for recv only
/*target is another host*/
socket_address.sll_pkttype = PACKET_BROADCAST; // for recv only
/*address length*/
socket_address.sll_halen = ETH_ALEN;
/*MAC - begin*/
socket_address.sll_addr[0] = 0x00;
socket_address.sll_addr[1] = 0x00;
socket_address.sll_addr[2] = 0x00;
socket_address.sll_addr[3] = 0x00;
socket_address.sll_addr[4] = 0x00;
socket_address.sll_addr[5] = 0x00;
/*MAC - end*/
socket_address.sll_addr[6] = 0x00; /*not used */
socket_address.sll_addr[7] = 0x00; /*not used */
memcpy ((void *) socket_address.sll_addr, (void *)tbuf , ETH_ALEN);
sleep(2);
send_result = sendto (sock, buffer, n, 0,
(struct sockaddr *) &socket_address,
sizeof (socket_address));
if (send_result == -1)
{
printf ("error sending packet %d\n", errno);
}
//write(fd, &u, len);
}
}
}
if (iphead[9] == IPPROTO_IGMP)
strcpy (proto, "IGMP");
if (iphead[9] == IPPROTO_TCP)
strcpy (proto, "TCP");
if (iphead[9] == IPPROTO_UDP)
strcpy (proto, "UDP");
printf ("Layer-4 protocol %s\n", proto);
printf ("TTL %d\n", iphead[8]);
}
}
else
if (ethhead[12] == 0x08 && ethhead[13] == 0x06)
{
printf ("proto = ARP");
}
else
printf ("proto = %02x:%02x\n", ethhead[12], ethhead[13]);
}
}
int
main (int argc, char **argv)
{
int sock;
struct ifreq ethreq;
if ((sock = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
{
perror ("socket");
exit (1);
}
/* Set the network card in promiscuous mode */
strncpy (ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl (sock, SIOCGIFFLAGS, ðreq) == -1)
{
perror ("ioctl");
close (sock);
exit (1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl (sock, SIOCSIFFLAGS, ðreq) == -1)
{
perror ("ioctl");
close (sock);
exit (1);
}
sendpack (sock); // ARP Request
while (1)
{
printf ("----------\n");
recvpack (sock);
}
}
No comments:
Post a Comment