

/************************************************************************/
/* arnudp100.c - sends a single UDP datagram with the source and	*/
/* destination address and port set to whatever you want.		*/
/* Known to work on:  Linux pre2.0.7 (486),  SunOS 5.4 (SPARC) and	*/
/* FreeBSD 2.1.0 (486).							*/
/* Old kernels such as SunOS 4.1 and Linux 1.2 will overwrite the	*/
/* source address with the real address of the interface.		*/
/* Should compile fine with just an ANSI compiler (such as gcc) under	*/
/* Linux and SunOS 4.1, but with SunOS 5.4 you may have to specify	*/
/* extra libraries on the command line:					*/
/* 	/usr/ucb/cc -o arnudp arnudp100.c -lsocket -lnsl		*/
/* I'll state the obvious - this needs to be run as root!  Do not use	*/
/* this program unless you know what you are doing, as it is possible	*/
/* that you could confuse parts of your network	/ internet.		*/
/* Written by R.T.Arnold (arny@geek.org.uk) for Netcraft Ltd.		*/
/* (c) copyright 1996 R.T. Arnold.  This is not free software.		*/
/************************************************************************/
 
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#ifndef INADDR_NONE
#define INADDR_NONE     0xffffffff
#endif

u_long getip(char*);
u_short getportudp(char*);

u_long cptol(u_char*);
u_char *stocp(u_char*,u_short);
u_char *ltocp(u_char*,u_long);

union shortunion { u_short s; u_char c[2]; };
union longunion { u_long l; u_char c[4]; };

struct sockaddr sa;

main(int argc,char **argv)
{
int fd;
int x=1;
u_long host;
u_short service;
struct sockaddr_in *p;
u_char gram[]=
	{
	0x45,	0x00,	0,	0,
	0x00,	0x00,	0x00,	0x00,
	0xFF,	0x11,	0x00,	0x00,
	0,	0,	0,	0,
	0,	0,	0,	0,

	0,	0,	0,	0,
	0x00,	0x12,	0x00,	0x00,

	'1','2','3','4','5','6','7','8','9','0'
	};

/* sanity check... */
if((sizeof(u_char)!=1)||(sizeof(u_short)!=2)||(sizeof(u_long)!=4))
	{
	fprintf(stderr,"error: integer types aren't the right size.\n");
	exit(1);
	};

/* it does seem odd that the total length needs to be in host byte order */
stocp(gram+2,(u_short)sizeof(gram));

if(argc!=5)
	{
	fprintf(stderr,"usage: %s sourcename sourceport destinationname destinationport\n",*argv);
	exit(1);
	};

/* fill in source/destination addresses/ports and the socket address...*/
if(strcmp(argv[1],"255.255.255.255")==0) host=0xffffffff; else if((host=getip(argv[1]))==INADDR_NONE) exit(1);
ltocp(gram+12,host);
if(strcmp(argv[3],"255.255.255.255")==0) host=0xffffffff; else if((host=getip(argv[3]))==INADDR_NONE) exit(1);
ltocp(gram+16,host);
p=(struct sockaddr_in*)&sa;
p->sin_family=AF_INET;
p->sin_addr.s_addr=host;
if(strcmp(argv[2],"0")==0) service=0; else if((service=getportudp(argv[2]))==0) exit(1);
stocp(gram+20,service);
if(strcmp(argv[4],"0")==0) service=0; else if((service=getportudp(argv[4]))==0) exit(1);
stocp(gram+22,service);

if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))== -1)
	{
	perror("socket");
	exit(1);
	};

#ifdef IP_HDRINCL
if (setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char*)&x,sizeof(x))<0)
	{
	perror("setsockopt IP_HDRINCL");
	exit(1);
        };
#else
fprintf(stderr,"the IP_HDRINCL option didn't exist on the system this was compliled on.\n");
#endif

if((sendto(fd,&gram,sizeof(gram),0,&sa,sizeof(sa)))== -1)
	{
	perror("sendto");
	exit(1);
	};

printf("datagram passed to kernel:");
for(x=0;x<(sizeof(gram)/sizeof(u_char));x++)
	{
	if(!(x%4)) putchar('\n');
	printf("%02x",gram[x]);
	};
putchar('\n');
return(0);
}

/* returns IP address (as a u_long) given a hostname string		*/

u_long getip(char *hostname)
{
u_long ip;
struct hostent *he;
if((ip=inet_addr(hostname))==INADDR_NONE)
	{
	if((he=gethostbyname(hostname))==NULL)
		{
		fprintf(stderr,"error: can't resolve hostname \"%s\"\n",hostname);
		return(INADDR_NONE);
		};
	if(he->h_addrtype!=AF_INET) fprintf(stderr,"warning: resolved address type is not AF_INET, will try to carry on anyway.\n");
	if(he->h_length!=4) fprintf(stderr,"warning: resolved address length is not 4, will try to carry on anyway.\n");
	ip=cptol((u_char*)*(he->h_addr_list));
	};
return(ip);
}

/* returns port given a UDP service name or port number			*/

u_short getportudp(char *service)
{
u_short port;
struct servent *se;
if((port=atoi(service))!=0) return(htons(port));
if((se=getservbyname(service,"udp"))==NULL)
	{
	fprintf(stderr,"error: unknown service \"%s\"\n",service);
	return(0);
	};
return(se->s_port);
}

/* the following functions convert between types, hopefully in a way thats portable */

u_long cptol(u_char *cp)
{
static union longunion l;
l.c[0]=cp[0];
l.c[1]=cp[1];
l.c[2]=cp[2];
l.c[3]=cp[3];
return(l.l);
}

u_char *stocp(u_char *cp,u_short us)
{
static union shortunion s;
s.s=us;
cp[0]=s.c[0];
cp[1]=s.c[1];
return(cp);
}

u_char *ltocp(u_char *cp,u_long ul)
{
static union longunion l;
l.l=ul;
cp[0]=l.c[0];
cp[1]=l.c[1];
cp[2]=l.c[2];
cp[3]=l.c[3];
return(cp);
}


