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, version 2
27**
28**  mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of
29**  Leland Stanford Junior University.
30**  - Original license can be found in the "doc/mrouted-LINCESE" file.
31**
32*/
33
34#include "defs.h"
35#include <linux/sockios.h>
36#ifdef USE_ATH_HEADER
37#include <sys/ioctl.h>
38#include <fcntl.h>
39#include <unistd.h>
40#endif
41
42
43struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc;
44
45/*
46** Builds up a vector with the interface of the machine. Calls to the other functions of
47** the module will fail if they are called before the vector is build.
48**
49*/
50void buildIfVc() {
51    struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] )  ];
52    struct ifreq *IfEp;
53
54    int Sock;
55
56    if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
57        igmp_syslog( LOG_ERR, errno, "RAW socket open" );
58
59    /* get If vector
60     */
61    {
62        struct ifconf IoCtlReq;
63
64        IoCtlReq.ifc_buf = (void *)IfVc;
65        IoCtlReq.ifc_len = sizeof( IfVc );
66
67        if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 )
68            igmp_syslog( LOG_ERR, errno, "ioctl SIOCGIFCONF" );
69
70        IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len);
71    }
72
73    /* loop over interfaces and copy interface info to IfDescVc
74     */
75    {
76        struct ifreq  *IfPt;
77        //struct IfDesc *IfDp;
78
79        // Temp keepers of interface params...
80        uint32 addr, subnet, mask;
81
82        for ( IfPt = IfVc; IfPt < IfEp; IfPt++ ) {
83            struct ifreq IfReq;
84            char FmtBu[ 32 ];
85
86            strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) );
87
88            // Currently don't set any allowed nets...
89            //IfDescEp->allowednets = NULL;
90
91            // Set the index to -1 by default.
92            IfDescEp->index = -1;
93
94            /* don't retrieve more info for non-IP interfaces
95             */
96            if ( IfPt->ifr_addr.sa_family != AF_INET ) {
97                IfDescEp->InAdr.s_addr = 0;  /* mark as non-IP interface */
98                IfDescEp++;
99                continue;
100            }
101
102            // Get the interface adress...
103            IfDescEp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr;
104            addr = IfDescEp->InAdr.s_addr;
105
106            memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) );
107
108            // Get the subnet mask...
109            if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
110                igmp_syslog(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
111            mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr;
112            subnet = addr & mask;
113
114            // Get the physical index of the Interface
115            if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0)
116                igmp_syslog(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name);
117
118            igmp_syslog(LOG_DEBUG, 0, "Physical Index value of IF '%s' is %d",
119                IfDescEp->Name, IfReq.ifr_ifindex);
120
121
122            /* get if flags
123            **
124            ** typical flags:
125            ** lo    0x0049 -> Running, Loopback, Up
126            ** ethx  0x1043 -> Multicast, Running, Broadcast, Up
127            ** ipppx 0x0091 -> NoArp, PointToPoint, Up
128            ** grex  0x00C1 -> NoArp, Running, Up
129            ** ipipx 0x00C1 -> NoArp, Running, Up
130            */
131            if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 )
132                igmp_syslog( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" );
133
134            IfDescEp->Flags = IfReq.ifr_flags;
135
136            // Insert the verified subnet as an allowed net...
137            IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList));
138            if(IfDescEp->allowednets == NULL) igmp_syslog(LOG_ERR, 0, "Out of memory !");
139
140            // Create the network address for the IF..
141            IfDescEp->allowednets->next = NULL;
142            IfDescEp->allowednets->subnet_mask = mask;
143            IfDescEp->allowednets->subnet_addr = subnet;
144
145            // Set the default params for the IF...
146            IfDescEp->state         = IF_STATE_DOWNSTREAM;
147            IfDescEp->robustness    = DEFAULT_ROBUSTNESS;
148            IfDescEp->threshold     = DEFAULT_THRESHOLD;   /* ttl limit */
149            IfDescEp->ratelimit     = DEFAULT_RATELIMIT;
150
151
152            // Debug igmp_syslog the result...
153            IF_DEBUG igmp_syslog( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
154                 IfDescEp->Name,
155                 fmtInAdr( FmtBu, IfDescEp->InAdr ),
156                 IfDescEp->Flags,
157                 inetFmts(subnet,mask, s1));
158
159            IfDescEp++;
160        }
161    }
162
163    close( Sock );
164}
165
166#ifdef USE_ATH_HEADER
167int
168initSnoopBr()
169{
170    unsigned Ix;
171    struct IfDesc *Dp;
172
173    // Join the all routers group on downstream vifs...
174    for (Ix = 0; (Dp = getIfByIx(Ix)); Ix++) {
175        // If this is a downstream vif, we should join the All routers group...
176        if ((Dp->state == IF_STATE_DOWNSTREAM)
177            && Dp->InAdr.s_addr && !(Dp->Flags & IFF_LOOPBACK)){
178
179            addVIF(Dp);
180
181#if 0
182            joinMcGroup(confFD /*getMcGroupSock()*/, Dp, allrouters_group);
183            IF_DEBUG log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s",
184                         inetFmt(allrouters_group, s1),
185                         inetFmt(Dp->InAdr.s_addr, s2));
186#endif
187
188        }
189    }
190
191    return 0;
192}
193
194int
195clearSnoopBr()
196{
197    unsigned Ix;
198    struct IfDesc *Dp;
199
200    // Join the all routers group on downstream vifs...
201    for (Ix = 0; (Dp = getIfByIx(Ix)); Ix++) {
202        // If this is a downstream vif, we should join the All routers group...
203        if ((Dp->state == IF_STATE_DOWNSTREAM)
204            && Dp->InAdr.s_addr && !(Dp->Flags & IFF_LOOPBACK)){
205
206            //delVIF(Dp);
207            Dp->state = IF_STATE_DISABLED;
208
209#if 0
210            leaveMcGroup(confFD /*getMcGroupSock()*/, Dp, allrouters_group);
211            IF_DEBUG log(LOG_DEBUG, 0, "Leaving all-routers group %s on vif %s",
212                         inetFmt(allrouters_group, s1),
213                         inetFmt(Dp->InAdr.s_addr, s2));
214#endif
215
216        }
217    }
218
219    return 0;
220}
221#endif
222
223/*
224** Returns a pointer to the IfDesc of the interface 'IfName'
225**
226** returns: - pointer to the IfDesc of the requested interface
227**          - NULL if no interface 'IfName' exists
228**
229*/
230struct IfDesc *getIfByName( const char *IfName ) {
231    struct IfDesc *Dp;
232
233    for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ )
234        if ( ! strcmp( IfName, Dp->Name ) )
235            return Dp;
236
237    return NULL;
238}
239
240/*
241** Returns a pointer to the IfDesc of the interface 'Ix'
242**
243** returns: - pointer to the IfDesc of the requested interface
244**          - NULL if no interface 'Ix' exists
245**
246*/
247struct IfDesc *getIfByIx( unsigned Ix ) {
248    struct IfDesc *Dp = &IfDescVc[ Ix ];
249    return Dp < IfDescEp ? Dp : NULL;
250}
251
252/**
253*   Returns a pointer to the IfDesc whose subnet matches
254*   the supplied IP adress. The IP must match a interfaces
255*   subnet, or any configured allowed subnet on a interface.
256*/
257struct IfDesc *getIfByAddress( uint32 ipaddr ) {
258
259    struct IfDesc       *Dp;
260    struct SubnetList   *currsubnet;
261
262    for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) {
263        // Loop through all registered allowed nets of the VIF...
264        for(currsubnet = Dp->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) {
265            // Check if the ip falls in under the subnet....
266            if((ipaddr & currsubnet->subnet_mask) == currsubnet->subnet_addr) {
267                return Dp;
268            }
269        }
270    }
271    return NULL;
272}
273
274
275/**
276*   Returns a pointer to the IfDesc whose subnet matches
277*   the supplied IP adress. The IP must match a interfaces
278*   subnet, or any configured allowed subnet on a interface.
279*/
280struct IfDesc *getIfByVifIndex( unsigned vifindex ) {
281    struct IfDesc       *Dp;
282    if(vifindex>0) {
283        for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) {
284            if(Dp->index == vifindex) {
285                return Dp;
286            }
287        }
288    }
289    return NULL;
290}
291
292
293/**
294*   Function that checks if a given ipaddress is a valid
295*   address for the supplied VIF.
296*/
297int isAdressValidForIf( struct IfDesc* intrface, uint32 ipaddr ) {
298    struct SubnetList   *currsubnet;
299
300    if(intrface == NULL) {
301        return 0;
302    }
303    // Loop through all registered allowed nets of the VIF...
304    for(currsubnet = intrface->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) {
305
306        /*
307        IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Testing %s for subnet %s, mask %s: Result net: %s",
308            inetFmt(ipaddr, s1),
309            inetFmt(currsubnet->subnet_addr, s2),
310            inetFmt(currsubnet->subnet_mask, s3),
311            inetFmt((ipaddr & currsubnet->subnet_mask), s4)
312            );
313            */
314
315        // Check if the ip falls in under the subnet....
316        if((ipaddr & currsubnet->subnet_mask) == currsubnet->subnet_addr) {
317            return 1;
318        }
319    }
320    return 0;
321}
322
323
324