1 /*
2 ** igmpproxy - IGMP proxy based multicast router
3 ** Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 **
19 **----------------------------------------------------------------------------
20 **
21 ** This software is derived work from the following software. The original
22 ** source code has been modified from it's original state by the author
23 ** of igmpproxy.
24 **
25 ** smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
26 ** - Licensed under the GNU General Public License, either version 2 or
27 ** any later version.
28 **
29 ** mrouted 3.9-beta3 - Copyright (C) 2002 by The Board of Trustees of
30 ** Leland Stanford Junior University.
31 ** - Licensed under the 3-clause BSD license, see Stanford.txt file.
32 **
33 */
34
35 #include "igmpproxy.h"
36
37 /* We need a temporary copy to not break strict aliasing rules */
s_addr_from_sockaddr(const struct sockaddr * addr)38 static inline uint32_t s_addr_from_sockaddr(const struct sockaddr *addr) {
39 struct sockaddr_in addr_in;
40 memcpy(&addr_in, addr, sizeof(addr_in));
41 return addr_in.sin_addr.s_addr;
42 }
43
44 struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc;
45
46 /* aimwang: add for detect interface and rebuild IfVc record */
47 /***************************************************
48 * TODO: Only need run me when detect downstream changed.
49 * For example: /etc/ppp/ip-up & ip-down can touch a file /tmp/ppp_changed
50 * So I can check if the file exist then run me and delete the file.
51 ***************************************************/
rebuildIfVc()52 void rebuildIfVc () {
53 struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ];
54 struct ifreq *IfEp;
55 struct ifconf IoCtlReq;
56 struct IfDesc *Dp;
57 struct ifreq *IfPt, *IfNext;
58 uint32_t addr, subnet, mask;
59 int Sock;
60
61 // Get the config.
62 struct Config *config = getCommonConfig();
63
64 if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
65 my_log( LOG_ERR, errno, "RAW socket open" );
66
67 // aimwang: set all downstream IF as lost, for check IF exist or gone.
68 for (Dp = IfDescVc; Dp < IfDescEp; Dp++) {
69 if (Dp->state == IF_STATE_DOWNSTREAM) {
70 Dp->state = IF_STATE_LOST;
71 }
72 }
73
74 IoCtlReq.ifc_buf = (void *)IfVc;
75 IoCtlReq.ifc_len = sizeof( IfVc );
76
77 if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 )
78 my_log( LOG_ERR, errno, "ioctl SIOCGIFCONF" );
79
80 IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len);
81
82 for ( IfPt = IfVc; IfPt < IfEp; IfPt = IfNext ) {
83 struct ifreq IfReq;
84 char FmtBu[ 32 ];
85
86 IfNext = (struct ifreq *)((char *)&IfPt->ifr_addr +
87 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
88 IfPt->ifr_addr.sa_len
89 #else
90 sizeof(struct sockaddr_in)
91 #endif
92 );
93 if (IfNext < IfPt + 1)
94 IfNext = IfPt + 1;
95
96 for (Dp = IfDescVc; Dp < IfDescEp; Dp++) {
97 if (0 == strcmp(Dp->Name, IfPt->ifr_name)) {
98 break;
99 }
100 }
101
102 if (Dp == IfDescEp) {
103 strncpy( Dp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) );
104 }
105
106 if ( IfPt->ifr_addr.sa_family != AF_INET ) {
107 if (Dp == IfDescEp) {
108 IfDescEp++;
109 }
110 Dp->InAdr.s_addr = 0; /* mark as non-IP interface */
111 continue;
112 }
113
114 // Get the interface adress...
115 Dp->InAdr.s_addr = s_addr_from_sockaddr(&IfPt->ifr_addr);
116 addr = Dp->InAdr.s_addr;
117
118 memcpy( IfReq.ifr_name, Dp->Name, sizeof( IfReq.ifr_name ) );
119
120 // Get the subnet mask...
121 if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
122 my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
123 mask = s_addr_from_sockaddr(&IfReq.ifr_addr); // Do not use ifr_netmask as it is not available on freebsd
124 subnet = addr & mask;
125
126 if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 )
127 my_log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" );
128 Dp->Flags = IfReq.ifr_flags;
129
130 if (0x10d1 == Dp->Flags)
131 {
132 if ( ioctl( Sock, SIOCGIFDSTADDR, &IfReq ) < 0 )
133 my_log(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", IfReq.ifr_name);
134 addr = s_addr_from_sockaddr(&IfReq.ifr_dstaddr);
135 subnet = addr & mask;
136 }
137
138 if (Dp == IfDescEp) {
139 // Insert the verified subnet as an allowed net...
140 Dp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList));
141 if(IfDescEp->allowednets == NULL) {
142 my_log(LOG_ERR, 0, "Out of memory !");
143 }
144 Dp->allowednets->next = NULL;
145 Dp->state = IF_STATE_DOWNSTREAM;
146 Dp->robustness = DEFAULT_ROBUSTNESS;
147 Dp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
148 Dp->ratelimit = DEFAULT_RATELIMIT;
149 }
150
151 // Set the network address for the IF..
152 Dp->allowednets->subnet_mask = mask;
153 Dp->allowednets->subnet_addr = subnet;
154
155 // Set the state for the IF...
156 if (Dp->state == IF_STATE_LOST) {
157 Dp->state = IF_STATE_DOWNSTREAM;
158 }
159
160 // when IF become enabeld from downstream, addVIF to enable its VIF
161 if (Dp->state == IF_STATE_HIDDEN) {
162 my_log(LOG_NOTICE, 0, "%s [Hidden -> Downstream]", Dp->Name);
163 Dp->state = IF_STATE_DOWNSTREAM;
164 addVIF(Dp);
165 k_join(Dp, allrouters_group);
166 }
167
168 // addVIF when found new IF
169 if (Dp == IfDescEp) {
170 my_log(LOG_NOTICE, 0, "%s [New]", Dp->Name);
171 Dp->state = config->defaultInterfaceState;
172 addVIF(Dp);
173 k_join(Dp, allrouters_group);
174 IfDescEp++;
175 }
176
177 // Debug log the result...
178 my_log( LOG_DEBUG, 0, "rebuildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
179 Dp->Name,
180 fmtInAdr( FmtBu, Dp->InAdr ),
181 Dp->Flags,
182 inetFmts(subnet, mask, s1));
183 }
184
185 // aimwang: search not longer exist IF, set as hidden and call delVIF
186 for (Dp = IfDescVc; Dp < IfDescEp; Dp++) {
187 if (IF_STATE_LOST == Dp->state) {
188 my_log(LOG_NOTICE, 0, "%s [Downstream -> Hidden]", Dp->Name);
189 Dp->state = IF_STATE_HIDDEN;
190 k_leave(Dp, allrouters_group);
191 delVIF(Dp);
192 }
193 }
194
195 close( Sock );
196 }
197
198 /*
199 ** Builds up a vector with the interface of the machine. Calls to the other functions of
200 ** the module will fail if they are called before the vector is build.
201 **
202 */
buildIfVc(void)203 void buildIfVc(void) {
204 struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ];
205 struct ifreq *IfEp;
206 struct Config *config = getCommonConfig();
207
208 int Sock;
209
210 if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
211 my_log( LOG_ERR, errno, "RAW socket open" );
212
213 /* get If vector
214 */
215 {
216 struct ifconf IoCtlReq;
217
218 IoCtlReq.ifc_buf = (void *)IfVc;
219 IoCtlReq.ifc_len = sizeof( IfVc );
220
221 if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 )
222 my_log( LOG_ERR, errno, "ioctl SIOCGIFCONF" );
223
224 IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len);
225 }
226
227 /* loop over interfaces and copy interface info to IfDescVc
228 */
229 {
230 struct ifreq *IfPt, *IfNext;
231
232 // Temp keepers of interface params...
233 uint32_t addr, subnet, mask;
234
235 for ( IfPt = IfVc; IfPt < IfEp; IfPt = IfNext ) {
236 struct ifreq IfReq;
237 char FmtBu[ 32 ];
238
239 IfNext = (struct ifreq *)((char *)&IfPt->ifr_addr +
240 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
241 IfPt->ifr_addr.sa_len
242 #else
243 sizeof(struct sockaddr_in)
244 #endif
245 );
246 if (IfNext < IfPt + 1)
247 IfNext = IfPt + 1;
248
249 strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) );
250
251 // Currently don't set any allowed nets...
252 //IfDescEp->allowednets = NULL;
253
254 // Set the index to -1 by default.
255 IfDescEp->index = (unsigned int)-1;
256
257 /* don't retrieve more info for non-IP interfaces
258 */
259 if ( IfPt->ifr_addr.sa_family != AF_INET ) {
260 IfDescEp->InAdr.s_addr = 0; /* mark as non-IP interface */
261 IfDescEp++;
262 continue;
263 }
264
265 // Get the interface adress...
266 IfDescEp->InAdr.s_addr = s_addr_from_sockaddr(&IfPt->ifr_addr);
267 addr = IfDescEp->InAdr.s_addr;
268
269 memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) );
270
271 // Get the subnet mask...
272 if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
273 my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
274 mask = s_addr_from_sockaddr(&IfReq.ifr_addr); // Do not use ifr_netmask as it is not available on freebsd
275 subnet = addr & mask;
276
277 /* get if flags
278 **
279 ** typical flags:
280 ** lo 0x0049 -> Running, Loopback, Up
281 ** ethx 0x1043 -> Multicast, Running, Broadcast, Up
282 ** ipppx 0x0091 -> NoArp, PointToPoint, Up
283 ** grex 0x00C1 -> NoArp, Running, Up
284 ** ipipx 0x00C1 -> NoArp, Running, Up
285 */
286 if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 )
287 my_log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" );
288
289 IfDescEp->Flags = IfReq.ifr_flags;
290
291 // aimwang: when pppx get dstaddr for use
292 if (0x10d1 == IfDescEp->Flags)
293 {
294 if ( ioctl( Sock, SIOCGIFDSTADDR, &IfReq ) < 0 )
295 my_log(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", IfReq.ifr_name);
296 addr = s_addr_from_sockaddr(&IfReq.ifr_dstaddr);
297 subnet = addr & mask;
298 }
299
300 // Insert the verified subnet as an allowed net...
301 IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList));
302 if(IfDescEp->allowednets == NULL) my_log(LOG_ERR, 0, "Out of memory !");
303
304 // Create the network address for the IF..
305 IfDescEp->allowednets->next = NULL;
306 IfDescEp->allowednets->subnet_mask = mask;
307 IfDescEp->allowednets->subnet_addr = subnet;
308
309 // Set the default params for the IF...
310 IfDescEp->state = config->defaultInterfaceState;
311 IfDescEp->robustness = DEFAULT_ROBUSTNESS;
312 IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
313 IfDescEp->ratelimit = DEFAULT_RATELIMIT;
314
315 // Debug log the result...
316 my_log( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
317 IfDescEp->Name,
318 fmtInAdr( FmtBu, IfDescEp->InAdr ),
319 IfDescEp->Flags,
320 inetFmts(subnet,mask, s1));
321
322 IfDescEp++;
323 }
324 }
325
326 close( Sock );
327 }
328
329 /*
330 ** Returns a pointer to the IfDesc of the interface 'IfName'
331 **
332 ** returns: - pointer to the IfDesc of the requested interface
333 ** - NULL if no interface 'IfName' exists
334 **
335 */
getIfByName(const char * IfName)336 struct IfDesc *getIfByName( const char *IfName ) {
337 struct IfDesc *Dp;
338
339 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ )
340 if ( ! strcmp( IfName, Dp->Name ) )
341 return Dp;
342
343 return NULL;
344 }
345
346 /*
347 ** Returns a pointer to the IfDesc of the interface 'Ix'
348 **
349 ** returns: - pointer to the IfDesc of the requested interface
350 ** - NULL if no interface 'Ix' exists
351 **
352 */
getIfByIx(unsigned Ix)353 struct IfDesc *getIfByIx( unsigned Ix ) {
354 struct IfDesc *Dp = &IfDescVc[ Ix ];
355 return Dp < IfDescEp ? Dp : NULL;
356 }
357
358 /**
359 * Returns a pointer to the IfDesc whose subnet matches
360 * the supplied IP adress. The IP must match a interfaces
361 * subnet, or any configured allowed subnet on a interface.
362 */
getIfByAddress(uint32_t ipaddr)363 struct IfDesc *getIfByAddress( uint32_t ipaddr ) {
364
365 struct IfDesc *Dp;
366 struct SubnetList *currsubnet;
367 struct IfDesc *res = NULL;
368 uint32_t last_subnet_mask = 0;
369
370 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) {
371 // Loop through all registered allowed nets of the VIF...
372 for(currsubnet = Dp->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) {
373 // Check if the ip falls in under the subnet....
374 if(currsubnet->subnet_mask > last_subnet_mask && (ipaddr & currsubnet->subnet_mask) == currsubnet->subnet_addr) {
375 res = Dp;
376 last_subnet_mask = currsubnet->subnet_mask;
377 }
378 }
379 }
380 return res;
381 }
382
383
384 /**
385 * Returns a pointer to the IfDesc whose subnet matches
386 * the supplied IP adress. The IP must match a interfaces
387 * subnet, or any configured allowed subnet on a interface.
388 */
getIfByVifIndex(unsigned vifindex)389 struct IfDesc *getIfByVifIndex( unsigned vifindex ) {
390 struct IfDesc *Dp;
391 if(vifindex>0) {
392 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) {
393 if(Dp->index == vifindex) {
394 return Dp;
395 }
396 }
397 }
398 return NULL;
399 }
400
401
402 /**
403 * Function that checks if a given ipaddress is a valid
404 * address for the supplied VIF.
405 */
isAdressValidForIf(struct IfDesc * intrface,uint32_t ipaddr)406 int isAdressValidForIf( struct IfDesc* intrface, uint32_t ipaddr ) {
407 struct SubnetList *currsubnet;
408
409 if(intrface == NULL) {
410 return 0;
411 }
412
413 // Loop through all registered allowed nets of the VIF...
414 for(currsubnet = intrface->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) {
415 // Check if the ip falls in under the subnet....
416 if((ipaddr & currsubnet->subnet_mask) == (currsubnet->subnet_addr& currsubnet->subnet_mask)) {
417 return 1;
418 }
419 }
420 return 0;
421 }
422