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*   mroute-api.c
35*
36*   This module contains the interface routines to the Linux mrouted API
37*/
38
39
40#define USE_LINUX_IN_H
41#include "defs.h"
42
43// MAX_MC_VIFS from mclab.h must have same value as MAXVIFS from mroute.h
44#if MAX_MC_VIFS != MAXVIFS
45# error "constants don't match, correct mclab.h"
46#endif
47
48// need an IGMP socket as interface for the mrouted API
49// - receives the IGMP messages
50int         MRouterFD;        /* socket for all network I/O  */
51char        *recv_buf;           /* input packet buffer         */
52char        *send_buf;           /* output packet buffer        */
53
54
55// my internal virtual interfaces descriptor vector
56static struct VifDesc {
57    struct IfDesc *IfDp;
58} VifDescVc[ MAXVIFS ];
59
60
61
62/*
63** Initialises the mrouted API and locks it by this exclusively.
64**
65** returns: - 0 if the functions succeeds
66**          - the errno value for non-fatal failure condition
67*/
68int enableMRouter()
69{
70    int Va = 1;
71
72    if ( (MRouterFD  = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0 )
73        log( LOG_ERR, errno, "IGMP socket open" );
74
75    if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_INIT,
76                     (void *)&Va, sizeof( Va ) ) )
77        return errno;
78
79    return 0;
80}
81
82/*
83** Diables the mrouted API and relases by this the lock.
84**
85*/
86void disableMRouter()
87{
88    if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DONE, NULL, 0 )
89         || close( MRouterFD )
90       ) {
91        MRouterFD = 0;
92        log( LOG_ERR, errno, "MRT_DONE/close" );
93    }
94
95    MRouterFD = 0;
96}
97
98/*
99** Adds the interface '*IfDp' as virtual interface to the mrouted API
100**
101*/
102void addVIF( struct IfDesc *IfDp )
103{
104    struct vifctl VifCtl;
105    struct VifDesc *VifDp;
106
107    /* search free VifDesc
108     */
109    for ( VifDp = VifDescVc; VifDp < VCEP( VifDescVc ); VifDp++ ) {
110        if ( ! VifDp->IfDp )
111            break;
112    }
113
114    /* no more space
115     */
116    if ( VifDp >= VCEP( VifDescVc ) )
117        log( LOG_ERR, ENOMEM, "addVIF, out of VIF space" );
118
119    VifDp->IfDp = IfDp;
120
121    VifCtl.vifc_vifi  = VifDp - VifDescVc;
122    VifCtl.vifc_flags = 0;        /* no tunnel, no source routing, register ? */
123    VifCtl.vifc_threshold  = VifDp->IfDp->threshold;    // Packet TTL must be at least 1 to pass them
124    VifCtl.vifc_rate_limit = VifDp->IfDp->ratelimit;    // Ratelimit
125
126    VifCtl.vifc_lcl_addr.s_addr = VifDp->IfDp->InAdr.s_addr;
127    VifCtl.vifc_rmt_addr.s_addr = INADDR_ANY;
128
129    // Set the index...
130    VifDp->IfDp->index = VifCtl.vifc_vifi;
131
132    log( LOG_NOTICE, 0, "adding VIF, Ix %d Fl 0x%x IP 0x%08x %s, Threshold: %d, Ratelimit: %d",
133         VifCtl.vifc_vifi, VifCtl.vifc_flags,  VifCtl.vifc_lcl_addr.s_addr, VifDp->IfDp->Name,
134         VifCtl.vifc_threshold, VifCtl.vifc_rate_limit);
135
136    IF_DEBUG {
137        struct SubnetList *currSubnet;
138        for(currSubnet = IfDp->allowednets; currSubnet; currSubnet = currSubnet->next) {
139            log(LOG_DEBUG, 0, "        Network for [%s] : %s",
140                IfDp->Name,
141                inetFmts(currSubnet->subnet_addr, currSubnet->subnet_mask, s1));
142        }
143    }
144
145    if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_VIF,
146                     (char *)&VifCtl, sizeof( VifCtl ) ) )
147        log( LOG_ERR, errno, "MRT_ADD_VIF" );
148
149}
150
151/*
152** Adds the multicast routed '*Dp' to the kernel routes
153**
154** returns: - 0 if the function succeeds
155**          - the errno value for non-fatal failure condition
156*/
157int addMRoute( struct MRouteDesc *Dp )
158{
159    struct mfcctl CtlReq;
160
161    CtlReq.mfcc_origin    = Dp->OriginAdr;
162    CtlReq.mfcc_mcastgrp  = Dp->McAdr;
163    CtlReq.mfcc_parent    = Dp->InVif;
164
165    /* copy the TTL vector
166     */
167    if (    sizeof( CtlReq.mfcc_ttls ) != sizeof( Dp->TtlVc )
168            || VCMC( CtlReq.mfcc_ttls ) != VCMC( Dp->TtlVc )
169       )
170        log( LOG_ERR, 0, "data types doesn't match in " __FILE__ ", source adaption needed !" );
171
172    memcpy( CtlReq.mfcc_ttls, Dp->TtlVc, sizeof( CtlReq.mfcc_ttls ) );
173
174    {
175        char FmtBuO[ 32 ], FmtBuM[ 32 ];
176
177        log( LOG_NOTICE, 0, "Adding MFC: %s -> %s, InpVIf: %d",
178             fmtInAdr( FmtBuO, CtlReq.mfcc_origin ),
179             fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ),
180             CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent
181           );
182    }
183
184    if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_MFC,
185                     (void *)&CtlReq, sizeof( CtlReq ) ) )
186        log( LOG_WARNING, errno, "MRT_ADD_MFC" );
187}
188
189/*
190** Removes the multicast routed '*Dp' from the kernel routes
191**
192** returns: - 0 if the function succeeds
193**          - the errno value for non-fatal failure condition
194*/
195int delMRoute( struct MRouteDesc *Dp )
196{
197    struct mfcctl CtlReq;
198
199    CtlReq.mfcc_origin    = Dp->OriginAdr;
200    CtlReq.mfcc_mcastgrp  = Dp->McAdr;
201    CtlReq.mfcc_parent    = Dp->InVif;
202
203    /* clear the TTL vector
204     */
205    memset( CtlReq.mfcc_ttls, 0, sizeof( CtlReq.mfcc_ttls ) );
206
207    {
208        char FmtBuO[ 32 ], FmtBuM[ 32 ];
209
210        log( LOG_NOTICE, 0, "Removing MFC: %s -> %s, InpVIf: %d",
211             fmtInAdr( FmtBuO, CtlReq.mfcc_origin ),
212             fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ),
213             CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent
214           );
215    }
216
217    if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DEL_MFC,
218                     (void *)&CtlReq, sizeof( CtlReq ) ) )
219        log( LOG_WARNING, errno, "MRT_DEL_MFC" );
220}
221
222/*
223** Returns for the virtual interface index for '*IfDp'
224**
225** returns: - the vitrual interface index if the interface is registered
226**          - -1 if no virtual interface exists for the interface
227**
228*/
229int getVifIx( struct IfDesc *IfDp )
230{
231    struct VifDesc *Dp;
232
233    for ( Dp = VifDescVc; Dp < VCEP( VifDescVc ); Dp++ )
234        if ( Dp->IfDp == IfDp )
235            return Dp - VifDescVc;
236
237    return -1;
238}
239
240
241
242