a80ead644acf2f48c099dd23cf7593a94a55c7e3
[udp-broadcast-relay.git] / main.c
1 /*
2 ******************************************************************
3 udp_broadcast_relay
4         Relays UDP broadcasts to other networks, forging
5         the sender address.
6
7 Copyright (c) 2003 Joachim Breitner <mail@joachim-breitner.de>
8
9 Based upon:
10 udp_broadcast_fw ; Forwards UDP broadcast packets to all local 
11         interfaces as though they originated from sender
12         
13 Copyright (C) 2002  Nathan O'Sullivan
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 2
18 of the License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 GNU General Public License for more details.
24 ******************************************************************
25
26 Thanks:
27
28 Arny <cs6171@scitsc.wlv.ac.uk> 
29 - public domain UDP spoofing code
30 http://www.netfor2.com/ip.htm
31 - IP/UDP packet formatting info
32
33 */
34
35 #define MAXIFS  256
36 #define DPRINT  printf
37 #define IPHEADER_LEN 20
38 #define UDPHEADER_LEN 8
39 #define HEADER_LEN (IPHEADER_LEN + UDPHEADER_LEN)
40 #define DEBUG
41  
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <netinet/in_systm.h>
45 #include <netinet/in.h>
46 #include <netinet/ip.h>
47 #include <netinet/udp.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <arpa/inet.h>
51 #include <stdio.h>
52 #include <linux/if.h>
53 #include <sys/ioctl.h>
54
55 main(int argc,char **argv)
56 {
57         /* We use two sockets - one for receiving broadcast packets (type UDP), and
58            one for spoofing them (type RAW) */
59         int fd,rcv;
60
61         /* Structure holds info on local interfaces */
62         struct ifreq reqbuf;
63         int maxifs;
64                 
65         /* list of addresses and interface numbers on local machine */
66         // struct sockaddr_in addr[MAXIFS];
67         struct {
68                 struct sockaddr_in brdaddr;
69                 int ifindex;
70         } ifs[MAXIFS];
71         
72         /* Address broadcast packet was sent from */
73         struct sockaddr_in rcv_addr;
74         
75         /* Incoming message read via rcvsmsg */
76         struct msghdr rcv_msg;
77         struct iovec iov;
78         u_char pkt_infos[16384];
79
80         int x=1, len;
81         
82         u_char gram[4096]=
83         {
84                 0x45,   0x00,   0x00,   0x26,
85                 0x12,   0x34,   0x00,   0x00,
86                 0xFF,   0x11,   0,      0,
87                 0,      0,      0,      0,
88                 0,      0,      0,      0,
89                 0,      0,      0,      0,
90                 0x00,   0x12,   0x00,   0x00,
91                 '1','2','3','4','5','6','7','8','9','0'
92         };
93
94         iov.iov_base = gram+ HEADER_LEN; 
95         iov.iov_len = 4006 - HEADER_LEN - 1;
96         
97         rcv_msg.msg_name = &rcv_addr;
98         rcv_msg.msg_namelen = sizeof(rcv_addr);
99         rcv_msg.msg_iov = &iov;
100         rcv_msg.msg_iovlen = 1;
101         rcv_msg.msg_control = pkt_infos;
102         rcv_msg.msg_controllen = sizeof(pkt_infos);
103         struct cmsghdr *cmsg;
104         int *ttlptr=NULL;
105         int rcv_ifindex;
106         
107         /* ARGS */
108         u_int16_t port;
109         u_char id;
110         u_char ttl;
111
112         if(argc < 5)
113         {
114                 fprintf(stderr,"usage: %s id udp-port dev1 dev2 ...\n",*argv);
115                 fprintf(stderr,"This program listens for broadcast packets on the specified udp-port\n"
116                         "and then forwards them to each other given interface.  Packets are sent\n"
117                         "such that they appear to have come from the original broadcaster. When using\n"
118                         "multiple instances for the same port on the same network, they must have the\n"
119                         "a different id.\n");
120                 exit(1);
121         };
122         
123         if ((id = atoi(argv[1])) == 0)
124         {
125                 fprintf (stderr,"ID argument not valid\n");
126                 exit(1);
127         }
128         argc--;
129         argv++;
130
131         if (id < 1 || id > 99)
132         {
133                 fprintf (stderr,"ID argument %i not between 1 and 99\n",id);
134                 exit(1);
135         }
136         ttl = id+64;
137         gram[8] = ttl; 
138
139         if ((port = atoi(argv[1])) == 0)
140         {
141                 fprintf (stderr,"Port argument not valid\n");
142                 exit(1);
143         }
144         argc--;
145         argv++;
146
147         /* We need to find out what IP's are bound to this host - set up a temporary socket to do so */
148         if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
149         {
150                 perror("socket");
151                 fprintf(stderr,"You must be root to create a raw socket\n");
152                 exit(1);
153         };
154         DPRINT ("ID: %i (ttl: %i), Port %i\n",id,ttl,port);
155
156         /* For each interface on the command line */
157         for (maxifs=0;argc>1;argc--,argv++)
158         {
159                 strncpy(reqbuf.ifr_name,argv[1],IFNAMSIZ);
160
161                 /* Request index for this interface */
162                 if (ioctl(fd,SIOCGIFINDEX, &reqbuf) < 0) {
163                         perror("ioctl(SIOCGIFINDEX)");
164                         exit(1);
165                 }
166                 
167                 /* Save the index for later use */      
168                 ifs[maxifs].ifindex = reqbuf.ifr_ifindex;
169                 
170                 /* Request flags for this interface */
171                 if (ioctl(fd,SIOCGIFFLAGS, &reqbuf) < 0) {
172                         perror("ioctl(SIOCGIFFLAGS)");
173                         exit(1);
174                 }
175
176                 /* if the interface is not up or a loopback, ignore it */
177                 if ((reqbuf.ifr_flags & IFF_UP) == 0 ||
178                     (reqbuf.ifr_flags & IFF_BROADCAST) == 0||
179                     (reqbuf.ifr_flags & IFF_LOOPBACK) )
180                         continue;
181
182                 /* Request the IP address for this interface */
183                 if (ioctl(fd,SIOCGIFBRDADDR, &reqbuf) < 0) {
184                         perror("ioctl(SIOCGIFBRDADDR)");
185                         exit(1);
186                 }
187
188                 /* Save the address for later use */
189                 bcopy(  (struct sockaddr_in *)&reqbuf.ifr_addr,
190                         &ifs[maxifs].brdaddr,
191                         sizeof(struct sockaddr_in) );
192
193                 DPRINT("%s: %i / %s\n",
194                         reqbuf.ifr_name,
195                         ifs[maxifs].ifindex,
196                         inet_ntoa(ifs[maxifs].brdaddr.sin_addr) );
197
198                 maxifs++;
199         }
200         maxifs--;
201         
202         /* Free our allocated buffer and close the socket */
203         close(fd);
204
205         /* Create our broadcast socket */
206         if((rcv=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
207         {
208                 perror("socket");
209                 exit(1);
210         };
211         x = 1;
212         if(setsockopt(rcv, SOL_SOCKET, SO_BROADCAST, (char*) &x, sizeof(int))<0){
213                 perror("SO_BROADCAST on rcv");
214                 exit(1);
215         };
216         if(setsockopt(rcv, SOL_IP, IP_RECVTTL, (char*) &x, sizeof(int))<0){
217                 perror("IP_RECVTTL on rcv");
218                 exit(1);
219         };
220         if(setsockopt(rcv, SOL_IP, IP_PKTINFO, (char*) &x, sizeof(int))<0){
221                 perror("IP_PKTINFO on rcv");
222                 exit(1);
223         };
224
225         /* We bind it to broadcast addr on the given port */
226         rcv_addr.sin_family = AF_INET;
227         rcv_addr.sin_port = htons(port);
228         rcv_addr.sin_addr.s_addr = INADDR_ANY;
229
230         if ( bind (rcv, (struct sockaddr *)&rcv_addr, sizeof(struct sockaddr_in) ) < 0 )
231         {
232                 perror("bind");
233                 fprintf(stderr,"A program is already bound to the broadcast address for the given port\n");
234                 exit(1);
235         }
236         
237         /* Set up a raw socket for sending our packets through */
238         if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
239         {
240                 perror("socket");
241                 exit(1);
242         };
243
244         /* Set dest port to that provided on command line */
245         *(u_short*)(gram+22)=(u_short)htons(port);
246         
247         x=1;
248         if (setsockopt(fd,SOL_SOCKET,SO_BROADCAST,(char*)&x,sizeof(x))<0)
249         {
250                 perror("setsockopt SO_BROADCAST");
251                 exit(1);
252         };
253
254         /* Enable IP header stuff on the raw socket */
255         #ifdef IP_HDRINCL
256         x=1;
257         if (setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char*)&x,sizeof(x))<0)
258         {
259                 perror("setsockopt IP_HDRINCL");
260                 exit(1);
261         };
262         #else
263         #error IP_HDRINCL support is required
264         #endif
265
266         /* Fork to background */
267   #ifndef DEBUG
268   if (fork())
269     exit(0);
270
271   fclose(stdin);
272   fclose(stdout);
273   fclose(stderr);
274   #endif
275
276   DPRINT("Done Initializing\n\n");
277
278         for (;;)
279         {
280                 /* Receive a broadcast packet */
281                 // x = sizeof(struct sockaddr_in);
282                 // len = recvfrom(rcv,gram+ HEADER_LEN,4006 - HEADER_LEN - 1,0,&rcv_addr,&x);
283                 len = recvmsg(rcv,&rcv_msg,0);
284                 if (len <= 0) continue; /* ignore broken packets */
285
286                 /* Find the ttl */
287                 ttlptr=NULL;
288                 if (rcv_msg.msg_controllen>0)
289                   for (cmsg=CMSG_FIRSTHDR(&rcv_msg);cmsg;cmsg=CMSG_NXTHDR(&rcv_msg,cmsg)) {
290                     if (cmsg->cmsg_type==IP_TTL) {
291                       ttlptr = (int *)CMSG_DATA(cmsg);
292                     }
293                     if (cmsg->cmsg_type==IP_PKTINFO) {
294                       rcv_ifindex=((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_ifindex;
295                     }
296                   }
297
298                 if (ttlptr == NULL) {
299                         perror("TTL not found\n");
300                         exit(1);
301                 }
302                 if (*ttlptr == ttl) {
303                         DPRINT ("Got local packge (TTL %i) on interface %i\n",*ttlptr,rcv_ifindex);
304                         continue;
305                 }
306                 
307
308                 gram[HEADER_LEN + len] =0;
309                 DPRINT("Got remote package:\n");
310                 DPRINT("Content:\t%s\n",gram+HEADER_LEN);
311                 DPRINT("TTL:\t\t%i\n",*ttlptr);
312                 DPRINT("Interface:\t%i\n",rcv_ifindex);
313                 DPRINT("From:\t\t%s:%d\n",inet_ntoa(rcv_addr.sin_addr),rcv_addr.sin_port);
314         
315                 /* copy sender's details into our datagram as the source addr */        
316                 bcopy(&(rcv_addr.sin_addr.s_addr),(gram+12),4);
317                 *(u_short*)(gram+20)=(u_short)rcv_addr.sin_port;
318
319                 /* set the length of the packet */
320                 *(u_short*)(gram+24)=htons(8 + len);
321                 *(u_short*)(gram+2)=htons(28+len);
322
323                 /* Iterate through the local addresses and send packet to each one */
324                 for (x=0;x<=maxifs;x++)
325                 {
326                         if (ifs[x].ifindex == rcv_ifindex) continue;
327
328                         /* Set destination addr ip - port is set already*/
329                         bcopy(&(ifs[x].brdaddr.sin_addr.s_addr),(gram+16),4);   
330
331                         DPRINT ("Sent to %s:%d on interface %i\n", inet_ntoa(ifs[x].brdaddr.sin_addr),ntohs(*(u_short*)(gram+22)),ifs[x].ifindex);
332                                 
333                         /* Send the packet */
334                         if (sendto(fd,&gram,28+len,0,(struct sockaddr*)&ifs[x].brdaddr,sizeof(struct sockaddr)) < 0)
335                                 perror("sendto");
336                 }
337                 DPRINT ("\n");
338         }
339 }