Annotation of embedaddon/igmpproxy/src/igmp.c, revision 1.1.1.1
1.1 misho 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 Stanford.txt file.
31: **
32: */
33: /**
34: * igmp.h - Recieves IGMP requests, and handle them
35: * appropriately...
36: */
37:
38: #include "igmpproxy.h"
39:
40: // Globals
41: uint32_t allhosts_group; /* All hosts addr in net order */
42: uint32_t allrouters_group; /* All hosts addr in net order */
43:
44: extern int MRouterFD;
45:
46: /*
47: * Open and initialize the igmp socket, and fill in the non-changing
48: * IP header fields in the output packet buffer.
49: */
50: void initIgmp() {
51: struct ip *ip;
52:
53: recv_buf = malloc(RECV_BUF_SIZE);
54: send_buf = malloc(RECV_BUF_SIZE);
55:
56: k_hdr_include(true); /* include IP header when sending */
57: k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering */
58: k_set_ttl(1); /* restrict multicasts to one hop */
59: k_set_loop(false); /* disable multicast loopback */
60:
61: ip = (struct ip *)send_buf;
62: memset(ip, 0, sizeof(struct ip));
63: /*
64: * Fields zeroed that aren't filled in later:
65: * - IP ID (let the kernel fill it in)
66: * - Offset (we don't send fragments)
67: * - Checksum (let the kernel fill it in)
68: */
69: ip->ip_v = IPVERSION;
70: ip->ip_hl = sizeof(struct ip) >> 2;
71: ip->ip_tos = 0xc0; /* Internet Control */
72: ip->ip_ttl = MAXTTL; /* applies to unicasts only */
73: ip->ip_p = IPPROTO_IGMP;
74:
75: allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
76: allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
77: }
78:
79: /**
80: * Finds the textual name of the supplied IGMP request.
81: */
82: char *igmpPacketKind(u_int type, u_int code) {
83: static char unknown[20];
84:
85: switch (type) {
86: case IGMP_MEMBERSHIP_QUERY: return "Membership query ";
87: case IGMP_V1_MEMBERSHIP_REPORT: return "V1 member report ";
88: case IGMP_V2_MEMBERSHIP_REPORT: return "V2 member report ";
89: case IGMP_V2_LEAVE_GROUP: return "Leave message ";
90:
91: default:
92: sprintf(unknown, "unk: 0x%02x/0x%02x ", type, code);
93: return unknown;
94: }
95: }
96:
97:
98: /**
99: * Process a newly received IGMP packet that is sitting in the input
100: * packet buffer.
101: */
102: void acceptIgmp(int recvlen) {
103: register uint32_t src, dst, group;
104: struct ip *ip;
105: struct igmp *igmp;
106: int ipdatalen, iphdrlen, igmpdatalen;
107:
108: if (recvlen < sizeof(struct ip)) {
109: my_log(LOG_WARNING, 0,
110: "received packet too short (%u bytes) for IP header", recvlen);
111: return;
112: }
113:
114: ip = (struct ip *)recv_buf;
115: src = ip->ip_src.s_addr;
116: dst = ip->ip_dst.s_addr;
117:
118: /*
119: * this is most likely a message from the kernel indicating that
120: * a new src grp pair message has arrived and so, it would be
121: * necessary to install a route into the kernel for this.
122: */
123: if (ip->ip_p == 0) {
124: if (src == 0 || dst == 0) {
125: my_log(LOG_WARNING, 0, "kernel request not accurate");
126: }
127: else {
128: struct IfDesc *checkVIF;
129:
130: // Check if the source address matches a valid address on upstream vif.
131: checkVIF = getIfByIx( upStreamVif );
132: if(checkVIF == 0) {
133: my_log(LOG_ERR, 0, "Upstream VIF was null.");
134: return;
135: }
136: else if(src == checkVIF->InAdr.s_addr) {
137: my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.",
138: inetFmt(src, s1), inetFmt(dst, s2));
139: return;
140: }
141: else if(!isAdressValidForIf(checkVIF, src)) {
142: my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
143: inetFmt(src, s1), inetFmt(dst, s2));
144: return;
145: }
146:
147: // Activate the route.
148: my_log(LOG_DEBUG, 0, "Route activate request from %s to %s",
149: inetFmt(src,s1), inetFmt(dst,s2));
150: activateRoute(dst, src);
151:
152:
153: }
154: return;
155: }
156:
157: iphdrlen = ip->ip_hl << 2;
158: ipdatalen = ip_data_len(ip);
159:
160: if (iphdrlen + ipdatalen != recvlen) {
161: my_log(LOG_WARNING, 0,
162: "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
163: inetFmt(src, s1), recvlen, iphdrlen, ipdatalen);
164: return;
165: }
166:
167: igmp = (struct igmp *)(recv_buf + iphdrlen);
168: group = igmp->igmp_group.s_addr;
169: igmpdatalen = ipdatalen - IGMP_MINLEN;
170: if (igmpdatalen < 0) {
171: my_log(LOG_WARNING, 0,
172: "received IP data field too short (%u bytes) for IGMP, from %s",
173: ipdatalen, inetFmt(src, s1));
174: return;
175: }
176:
177: my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s",
178: igmpPacketKind(igmp->igmp_type, igmp->igmp_code),
179: inetFmt(src, s1), inetFmt(dst, s2) );
180:
181: switch (igmp->igmp_type) {
182: case IGMP_V1_MEMBERSHIP_REPORT:
183: case IGMP_V2_MEMBERSHIP_REPORT:
184: acceptGroupReport(src, group, igmp->igmp_type);
185: return;
186:
187: case IGMP_V2_LEAVE_GROUP:
188: acceptLeaveMessage(src, group);
189: return;
190:
191: case IGMP_MEMBERSHIP_QUERY:
192: return;
193:
194: default:
195: my_log(LOG_INFO, 0,
196: "ignoring unknown IGMP message type %x from %s to %s",
197: igmp->igmp_type, inetFmt(src, s1),
198: inetFmt(dst, s2));
199: return;
200: }
201: }
202:
203:
204: /*
205: * Construct an IGMP message in the output packet buffer. The caller may
206: * have already placed data in that buffer, of length 'datalen'.
207: */
208: void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
209: struct ip *ip;
210: struct igmp *igmp;
211: extern int curttl;
212:
213: ip = (struct ip *)send_buf;
214: ip->ip_src.s_addr = src;
215: ip->ip_dst.s_addr = dst;
216: ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
217:
218: if (IN_MULTICAST(ntohl(dst))) {
219: ip->ip_ttl = curttl;
220: } else {
221: ip->ip_ttl = MAXTTL;
222: }
223:
224: igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
225: igmp->igmp_type = type;
226: igmp->igmp_code = code;
227: igmp->igmp_group.s_addr = group;
228: igmp->igmp_cksum = 0;
229: igmp->igmp_cksum = inetChksum((u_short *)igmp,
230: IGMP_MINLEN + datalen);
231: }
232:
233: /*
234: * Call build_igmp() to build an IGMP message in the output packet buffer.
235: * Then send the message from the interface with IP address 'src' to
236: * destination 'dst'.
237: */
238: void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
239: struct sockaddr_in sdst;
240: int setloop = 0, setigmpsource = 0;
241:
242: buildIgmp(src, dst, type, code, group, datalen);
243:
244: if (IN_MULTICAST(ntohl(dst))) {
245: k_set_if(src);
246: setigmpsource = 1;
247: if (type != IGMP_DVMRP || dst == allhosts_group) {
248: setloop = 1;
249: k_set_loop(true);
250: }
251: }
252:
253: memset(&sdst, 0, sizeof(sdst));
254: sdst.sin_family = AF_INET;
255: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
256: sdst.sin_len = sizeof(sdst);
257: #endif
258: sdst.sin_addr.s_addr = dst;
259: if (sendto(MRouterFD, send_buf,
260: MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
261: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
262: if (errno == ENETDOWN)
263: my_log(LOG_ERR, errno, "Sender VIF was down.");
264: else
265: my_log(LOG_INFO, errno,
266: "sendto to %s on %s",
267: inetFmt(dst, s1), inetFmt(src, s2));
268: }
269:
270: if(setigmpsource) {
271: if (setloop) {
272: k_set_loop(false);
273: }
274: // Restore original...
275: k_set_if(INADDR_ANY);
276: }
277:
278: my_log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
279: igmpPacketKind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
280: inetFmt(src, s1), inetFmt(dst, s2));
281: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>