Topic #98: udprelay.c

File udprelay.c, 7.3 KB (added by dani_lcfib, 12 years ago)

Codigo fuente de un relay udp, ideal para wol-relay

Line 
1/*
2    This program is free software: you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation, either version 3 of the License, or
5    (at your option) any later version.
6
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11
12    You should have received a copy of the GNU General Public License
13    along with this program.  If not, see <http://www.gnu.org/licenses/>.
14*/
15
16/*
17    Copyright 2010 Luke Bratch <l_bratch@yahoo.co.uk>
18
19    UDP header struct and modification method from udp-broadcast-relay [1].
20    I believe the struct was originally by cs6171@scitsc.wlv.ac.uk.
21
22    [1] http://www.joachim-breitner.de/udp-broadcast-relay/
23*/
24/*
25    Modificado LCFIB - UPC Daniel Sanchez 2012
26
27    Anyadimos la capacidad de enviar mensajes de broadcast a destinatario. Para poder
28    usar esta opcion hay que ser root.
29    Anyadimos funcion debugger
30
31*/
32
33#include <string.h>
34#include <arpa/inet.h>
35#include <stdio.h>
36#include <linux/if.h>
37
38int main(int argc, char *argv[]) {
39
40    /* Listening and destination ports */
41    unsigned short int lstport;
42    unsigned short int dstport;
43
44    /* Receiving and sending sockets */
45    int rcvfd;
46    int sndfd;
47
48    /* Destination addresses */
49    struct {
50        struct sockaddr_in dstaddr;
51    } dsts[argc - 4]; /* Anything after 4th arg is a destination address */
52    /* Number of destination addresses */
53    int dstcount;
54
55    /* Source packet */
56    struct msghdr rcvmsg;
57    struct iovec iov;
58    u_char pkt_info[16384];
59    int rcvlen;
60
61    /* Address of source packet */
62    struct sockaddr_in srcaddr;
63
64    /* For for loops */
65    int i;
66    /* For setsockopt() values */
67    int optval;
68    /* For debug */
69    int debug = 0; 
70
71
72    /* Outgoing UDP packet structure */
73    u_char packet[4096] = {
74        0x45, 0x00, 0x00, 0x26,
75        0x12, 0x34, 0x00, 0x00,
76        0xFF, 0x11, 0,    0,
77        0,    0,    0,    0,
78        0,    0,    0,    0,
79        0,    0,    0,    0,
80        0x00, 0x12, 0x00, 0x00,
81        '1','2','3','4','5','6','7','8','9','0'
82    };
83
84    /* Print some usage instructions */
85    if (argc < 5) {
86        fprintf(stderr, "Usage: %s LST-ADDR LST-PORT DST-PORT DST-ADDR [DST-ADDR]...\n"
87                        "\n"
88                        "bind()s to address LST-ADDR on port LST-PORT and retransmits UDP\n"
89                        "packets received to addresses(s) DST-ADDR(s) on port DST-PORT,\n"
90                        "with modified headers to reflect the new target.\n"
91                        "\n"
92                        "To receieve broadcast traffic, use a LST-ADDR of 0.0.0.0.  If\n"
93                        "a program is already listening on LST-PORT on LST-ADDR, you may\n"
94                        "listen on a broadcast address such as 255.255.255.255.\n"
95                        "\n"
96                        "Steam broadcasts to a number of different ports, so it is\n"
97                        "sufficient to listen on a different port to your game server.\n"
98                        "e.g. a LST-PORT of 27016 and a DST-PORT of 27015 will let you\n"
99                        "listen on a different port to a game server, but for it to still\n"
100                        "directly receive packets that were broadcast.\n",
101                        argv[0]);
102        return 1;
103    }
104
105    if (((lstport = atoi(argv[2])) == 0) || ((dstport = atoi(argv[3])) == 0)) {
106        fprintf(stderr, "lst-port or dst-port is invalid\n");
107        return 1;
108    }
109
110    /* Populate iovec */
111    iov.iov_base = packet + 28; /* Header length is 28 */
112    iov.iov_len = 3977; /* 4006 - header length - 1 */
113
114    /* Populate msghdr */
115    rcvmsg.msg_name = &srcaddr;
116    rcvmsg.msg_namelen = sizeof(srcaddr);
117    rcvmsg.msg_iov = &iov;
118    rcvmsg.msg_iovlen = 1;
119    rcvmsg.msg_control = pkt_info;
120    rcvmsg.msg_controllen = sizeof(pkt_info);
121
122    /* Enumerate destination addresses */
123    for (i = 0; i < argc - 4; i++) {
124        dsts[i].dstaddr.sin_family = AF_INET;
125        dsts[i].dstaddr.sin_port = htons(dstport);
126        if ((inet_pton(AF_INET, argv[i + 4], &dsts[i].dstaddr.sin_addr)) != 1) {
127            fprintf(stderr, "dst-addr%d is invalid\n", i + 1);
128            return 1;
129        }
130    }
131    /* Set number of destinations */
132    dstcount = i;
133
134    /* Create receiving socket */
135    if ((rcvfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
136        perror("rcvfd socket");
137        return 1;
138    }
139
140    /* Allow UDP broadcasts on receiving socket */
141    optval = 1;
142    if (setsockopt(rcvfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)) < 0) {
143        perror("setsockopt(rcvfd, SOL_SOCKET, SO_BROADCAST, ...)");
144        return 1;
145    };
146
147    /* Set properties of source address */
148    srcaddr.sin_family = AF_INET;
149    srcaddr.sin_port = htons(lstport);
150    if ((inet_pton(AF_INET, argv[1], &srcaddr.sin_addr.s_addr)) != 1) {
151        fprintf(stderr, "lst-addr is invalid\n");
152        return 1;
153    }
154
155    /* Bind the receiving socket */
156    if (bind(rcvfd, (struct sockaddr*)&srcaddr, sizeof(struct sockaddr_in)) < 0) {
157        perror("bind");
158         return 1;
159    }
160
161    /* Create sending socket */
162    if ((sndfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
163        perror("sndfd socket");
164        return 1;
165    }
166
167    /* Allow UDP broadcasts on sending socket -- LCFIB --*/
168    if (setsockopt (sndfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)) < 0) { 
169        perror("setsockopt(sndfd, SOL_SOCKET, SO_BROADCAST, ...)");
170        return 1;
171    }   
172
173    /* Set destination port in outgoing packet */
174    *(u_short *)(packet + 22) = (u_short)htons(dstport);
175
176    /* Allow setting outgoing header manually */
177    optval = 1;
178    if (setsockopt(sndfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int)) < 0) {
179        perror("setsockopt(sndfd, IPPROTO_IP, IP_HDRINCL, ...)");
180        return 1;
181    }
182
183    /* Main loop */
184    for ( ; ; ) {
185        /* Wait for a packet */
186        if (debug) printf("Waiting packet\n"); 
187        rcvlen = recvmsg(rcvfd, &rcvmsg, 0);
188
189        if (rcvlen < 1) {
190            /* Packet must not be broken */
191             continue;
192        }
193
194        // Debugging:
195        if (debug) printf("Recv: %s:%d\n",inet_ntoa(srcaddr.sin_addr),srcaddr.sin_port);
196
197        /* Grow packet */
198        packet[28 + rcvlen] = 0;
199
200        /* Copy source packet source address/port into outgoing packet */
201        bcopy(&(srcaddr.sin_addr.s_addr), (packet + 12), 4);
202        *(u_short *)(packet + 20) = (u_short)srcaddr.sin_port;
203
204        /* Set length of outgoing packet */
205        *(u_short *)(packet + 24) = htons(8 + rcvlen);
206        *(u_short *)(packet + 2) = htons(28 + rcvlen);
207
208        for (i = 0; i < dstcount; i++) {
209            /* Set destination of outgoing packet */
210            bcopy(&(dsts[i].dstaddr.sin_addr.s_addr), (packet + 16), 4);
211
212            /* Send outgoing packet */
213            if (sendto(sndfd, &packet, 28 + rcvlen, 0,
214                       (struct sockaddr *)&dsts[i].dstaddr,
215                       sizeof(struct sockaddr))
216                < 0) {
217                perror("sendto");
218            }
219
220            // Debugging:
221            if (debug) printf("Sent: %s:%d\n", inet_ntoa(dsts[i].dstaddr.sin_addr),
222                         ntohs(*(u_short *)(packet+22)));
223        }
224    }
225
226    return 0;
227}