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