b72ab36a81ad04bfae5f18941a523c5a32eee1b6
[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  if (debug) printf
37 #define IPHEADER_LEN 20
38 #define UDPHEADER_LEN 8
39 #define HEADER_LEN (IPHEADER_LEN + UDPHEADER_LEN)
40 #define TTL_ID_OFFSET 64
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 #include <stdlib.h>
55 #include <unistd.h>
56
57 /* list of addresses and interface numbers on local machine */
58 static struct {
59         struct sockaddr_in dstaddr;
60         int ifindex, raw_socket;
61 } ifs[MAXIFS];
62
63 /* Where we forge our packets */
64 static u_char gram[4096]=
65 {
66         0x45,   0x00,   0x00,   0x26,
67         0x12,   0x34,   0x00,   0x00,
68         0xFF,   0x11,   0,      0,
69         0,      0,      0,      0,
70         0,      0,      0,      0,
71         0,      0,      0,      0,
72         0x00,   0x12,   0x00,   0x00,
73         '1','2','3','4','5','6','7','8','9','0'
74 };
75
76 int main(int argc,char **argv)
77 {
78         /* Debugging, forking, other settings */
79         int debug, forking;
80         
81         u_int16_t port;
82         u_char id;
83         u_char ttl;
84
85         /* We use two sockets - one for receiving broadcast packets (type UDP), and
86            one for spoofing them (type RAW) */
87         int fd,rcv;
88
89         /* Structure holds info on local interfaces */
90         struct ifreq reqbuf;
91         int maxifs;
92                 
93         /* Address broadcast packet was sent from */
94         struct sockaddr_in rcv_addr;
95         
96         /* Incoming message read via rcvsmsg */
97         struct msghdr rcv_msg;
98         struct iovec iov;
99         u_char pkt_infos[16384];
100
101         /* various variables */
102         int x=1, len;
103         
104         struct cmsghdr *cmsg;
105         int *ttlptr=NULL;
106         int rcv_ifindex = 0;
107
108         iov.iov_base = gram+ HEADER_LEN; 
109         iov.iov_len = 4006 - HEADER_LEN - 1;
110         
111         rcv_msg.msg_name = &rcv_addr;
112         rcv_msg.msg_namelen = sizeof(rcv_addr);
113         rcv_msg.msg_iov = &iov;
114         rcv_msg.msg_iovlen = 1;
115         rcv_msg.msg_control = pkt_infos;
116         rcv_msg.msg_controllen = sizeof(pkt_infos);
117         
118         /* parsing the args */
119         if(argc < 5)
120         {
121                 fprintf(stderr,"usage: %s [-d] [-f] id udp-port dev1 dev2 ...\n",*argv);
122                 fprintf(stderr,"This program listens for broadcast packets on the specified udp-port\n"
123                         "and then forwards them to each other given interface.  Packets are sent\n"
124                         "such that they appear to have come from the original broadcaster. When using\n"
125                         "multiple instances for the same port on the same network, they must have the\n"
126                         "a different id.\n"
127                         "-d enables Debugging, -f forces forking to background\n");
128                 exit(1);
129         };
130         
131         if ((debug = (strcmp(argv[1],"-d") == 0)))
132         {
133                 argc--;
134                 argv++;
135                 DPRINT ("Debugging Mode enabled\n");
136         };
137         
138         if ((forking = (strcmp(argv[1],"-f") == 0)))
139         {
140                 argc--;
141                 argv++;
142                 DPRINT ("Forking Mode enabled (while debuggin? useless..)\n");
143         };
144
145         if ((id = atoi(argv[1])) == 0)
146         {
147                 fprintf (stderr,"ID argument not valid\n");
148                 exit(1);
149         }
150         argc--;
151         argv++;
152
153         if (id < 1 || id > 99)
154         {
155                 fprintf (stderr,"ID argument %i not between 1 and 99\n",id);
156                 exit(1);
157         }
158         ttl = id+TTL_ID_OFFSET;
159         gram[8] = ttl;
160         /* The id is used to detect packets we just sent, and is stored in the "ttl" field,
161          * which is not used with broadcast packets. Beware when using this with
162          * non-broadcast-packets */
163         
164         if ((port = atoi(argv[1])) == 0)
165         {
166                 fprintf (stderr,"Port argument not valid\n");
167                 exit(1);
168         }
169         argc--;
170         argv++;
171         
172         DPRINT ("ID: %i (ttl: %i), Port %i\n",id,ttl,port);
173
174
175         /* We need to find out what IP's are bound to this host - set up a temporary socket to do so */
176         if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
177         {
178                 perror("socket");
179                 fprintf(stderr,"You must be root to create a raw socket\n");
180                 exit(1);
181         };
182
183         /* For each interface on the command line */
184         for (maxifs=0;argc>1;argc--,argv++)
185         {
186                 int ioctl_request; 
187
188                 strncpy(reqbuf.ifr_name,argv[1],IFNAMSIZ);
189
190                 /* Request index for this interface */
191                 if (ioctl(fd,SIOCGIFINDEX, &reqbuf) < 0) {
192                         perror("ioctl(SIOCGIFINDEX)");
193                         exit(1);
194                 }
195                 
196                 /* Save the index for later use */      
197                 ifs[maxifs].ifindex = reqbuf.ifr_ifindex;
198                 
199                 /* Request flags for this interface */
200                 if (ioctl(fd,SIOCGIFFLAGS, &reqbuf) < 0) {
201                         perror("ioctl(SIOCGIFFLAGS)");
202                         exit(1);
203                 }
204
205                 /* if the interface is not up or a loopback, ignore it */
206                 if ((reqbuf.ifr_flags & IFF_UP) == 0 ||
207                     (reqbuf.ifr_flags & IFF_LOOPBACK) )
208                         continue;
209
210                 /* find the address type we need */
211                 if (reqbuf.ifr_flags & IFF_BROADCAST)
212                         ioctl_request = SIOCGIFBRDADDR;
213                 else 
214                         ioctl_request = SIOCGIFDSTADDR;
215                                 
216
217                 /* Request the broadcast/destination address for this interface */
218                 if (ioctl(fd,ioctl_request, &reqbuf) < 0) {
219                         perror("ioctl(SIOCGIFBRDADDR)");
220                         exit(1);
221                 }
222
223                 /* Save the address for later use */
224                 bcopy(  (struct sockaddr_in *)&reqbuf.ifr_addr,
225                         &ifs[maxifs].dstaddr,
226                         sizeof(struct sockaddr_in) );
227
228                 DPRINT("%s: %i / %s\n",
229                         reqbuf.ifr_name,
230                         ifs[maxifs].ifindex,
231                         inet_ntoa(ifs[maxifs].dstaddr.sin_addr) );
232
233                 /* Set up a one raw socket per interface for sending our packets through */
234                 if((ifs[maxifs].raw_socket = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
235                 {
236                         perror("socket");
237                         exit(1);
238                 };
239                 x=1;
240                 if (setsockopt(ifs[maxifs].raw_socket,SOL_SOCKET,SO_BROADCAST,(char*)&x,sizeof(x))<0)
241                 {
242                         perror("setsockopt SO_BROADCAST");
243                         exit(1);
244                 };
245                 /* bind socket to dedicated NIC (override routing table) */
246                 if (setsockopt(ifs[maxifs].raw_socket,SOL_SOCKET,SO_BINDTODEVICE,argv[1],strlen(argv[1])+1)<0)
247                 {
248                         perror("setsockopt IP_HDRINCL");
249                         exit(1);
250                 };
251                 /* Enable IP header stuff on the raw socket */
252                 #ifdef IP_HDRINCL
253                 x=1;
254                 if (setsockopt(ifs[maxifs].raw_socket,IPPROTO_IP,IP_HDRINCL,(char*)&x,sizeof(x))<0)
255                 {
256                         perror("setsockopt IP_HDRINCL");
257                         exit(1);
258                 };
259                 #else
260                 #error IP_HDRINCL support is required
261                 #endif
262
263                 /* ... and count it */
264                 maxifs++;
265         }
266         /* well, we want the max index, actually */
267         maxifs--;
268         DPRINT("found %i interfaces total\n",maxifs+1);
269         
270         /* Free our allocated buffer and close the socket */
271         close(fd);
272
273         /* Create our broadcast receiving socket */
274         if((rcv=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
275         {
276                 perror("socket");
277                 exit(1);
278         };
279
280         x = 1;
281         if(setsockopt(rcv, SOL_SOCKET, SO_BROADCAST, (char*) &x, sizeof(int))<0){
282                 perror("SO_BROADCAST on rcv");
283                 exit(1);
284         };
285         if(setsockopt(rcv, SOL_IP, IP_RECVTTL, (char*) &x, sizeof(int))<0){
286                 perror("IP_RECVTTL on rcv");
287                 exit(1);
288         };
289         if(setsockopt(rcv, SOL_IP, IP_PKTINFO, (char*) &x, sizeof(int))<0){
290                 perror("IP_PKTINFO on rcv");
291                 exit(1);
292         };
293
294         /* We bind it to broadcast addr on the given port */
295         rcv_addr.sin_family = AF_INET;
296         rcv_addr.sin_port = htons(port);
297         rcv_addr.sin_addr.s_addr = INADDR_ANY;
298
299         if ( bind (rcv, (struct sockaddr *)&rcv_addr, sizeof(struct sockaddr_in) ) < 0 )
300         {
301                 perror("bind");
302                 fprintf(stderr,"A program is already bound to the broadcast address for the given port\n");
303                 exit(1);
304         }
305
306         /* Set dest port to that was provided on command line */
307         *(u_short*)(gram+22)=(u_short)htons(port);
308
309         /* Fork to background */
310   if (! debug) {
311     if (forking && fork())
312       exit(0);
313
314     fclose(stdin);
315     fclose(stdout);
316     fclose(stderr);
317   }
318
319   DPRINT("Done Initializing\n\n");
320
321         for (;;) /* endless loop */
322         {
323                 /* Receive a broadcast packet */
324                 len = recvmsg(rcv,&rcv_msg,0);
325                 if (len <= 0) continue; /* ignore broken packets */
326
327                 /* Find the ttl and the receiving interface */
328                 ttlptr=NULL;
329                 if (rcv_msg.msg_controllen>0)
330                   for (cmsg=CMSG_FIRSTHDR(&rcv_msg);cmsg;cmsg=CMSG_NXTHDR(&rcv_msg,cmsg)) {
331                     if (cmsg->cmsg_type==IP_TTL) {
332                       ttlptr = (int *)CMSG_DATA(cmsg);
333                     }
334                     if (cmsg->cmsg_type==IP_PKTINFO) {
335                       rcv_ifindex=((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_ifindex;
336                     }
337                   }
338
339                 if (ttlptr == NULL) {
340                         perror("TTL not found on incoming packet\n");
341                         exit(1);
342                 }
343                 if (*ttlptr == ttl) {
344                         DPRINT ("Got local package (TTL %i) on interface %i\n",*ttlptr,rcv_ifindex);
345                         continue;
346                 }
347                 
348
349                 gram[HEADER_LEN + len] =0;
350                 DPRINT("Got remote package:\n");
351                 // DPRINT("Content:\t%s\n",gram+HEADER_LEN);
352                 DPRINT("TTL:\t\t%i\n",*ttlptr);
353                 DPRINT("Interface:\t%i\n",rcv_ifindex);
354                 DPRINT("From:\t\t%s:%d\n",inet_ntoa(rcv_addr.sin_addr),rcv_addr.sin_port);
355         
356                 /* copy sender's details into our datagram as the source addr */        
357                 bcopy(&(rcv_addr.sin_addr.s_addr),(gram+12),4);
358                 *(u_short*)(gram+20)=(u_short)rcv_addr.sin_port;
359
360                 /* set the length of the packet */
361                 *(u_short*)(gram+24)=htons(8 + len);
362                 *(u_short*)(gram+2)=htons(28+len);
363
364                 /* Iterate through our interfaces and send packet to each one */
365                 for (x=0;x<=maxifs;x++)
366                 {
367                         if (ifs[x].ifindex == rcv_ifindex) continue; /* no bounces, please */
368
369                         /* Set destination addr ip - port is set already */
370                         bcopy(&(ifs[x].dstaddr.sin_addr.s_addr),(gram+16),4);   
371
372                         DPRINT ("Sent to %s:%d on interface %i\n",
373                                 inet_ntoa(ifs[x].dstaddr.sin_addr), /* dst ip */
374                                 ntohs(*(u_short*)(gram+22)), /* dst port */
375                                 ifs[x].ifindex); /* interface number */
376                                 
377                         /* Send the packet */
378                         if (sendto(ifs[x].raw_socket,
379                                         &gram,
380                                         28+len,0,
381                                         (struct sockaddr*)&ifs[x].dstaddr,sizeof(struct sockaddr)
382                                 ) < 0)
383                                 perror("sendto");
384                 }
385                 DPRINT ("\n");
386         }
387 }