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