• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/omcproxy/src/omcproxy.c

  1 /*
  2  * Copyright 2015 Steven Barth <steven at midlink.org>
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *  http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  *
 16  */
 17 
 18 #include <stdio.h>
 19 #include <signal.h>
 20 #include <string.h>
 21 #include <stdlib.h>
 22 #include <netdb.h>
 23 #include <net/if.h>
 24 #include <unistd.h>
 25 
 26 #include <libubox/uloop.h>
 27 #include <libubox/blobmsg.h>
 28 
 29 #include "omcproxy.h"
 30 #include "proxy.h"
 31 
 32 enum {
 33         PROXY_ATTR_SOURCE,
 34         PROXY_ATTR_SCOPE,
 35         PROXY_ATTR_DEST,
 36         PROXY_ATTR_MAX,
 37 };
 38 
 39 static struct blobmsg_policy proxy_policy[PROXY_ATTR_MAX] = {
 40         [PROXY_ATTR_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING },
 41         [PROXY_ATTR_SCOPE] = { .name = "scope", .type = BLOBMSG_TYPE_STRING },
 42         [PROXY_ATTR_DEST] = { .name = "dest", .type = BLOBMSG_TYPE_ARRAY },
 43 };
 44 
 45 static int handle_proxy_set(void *data, size_t len, const struct proxy_options *opts)
 46 {
 47         struct blob_attr *tb[PROXY_ATTR_MAX], *c;
 48         blobmsg_parse(proxy_policy, PROXY_ATTR_MAX, tb, data, len);
 49 
 50         const char *name = ((c = tb[PROXY_ATTR_SOURCE])) ? blobmsg_get_string(c) : NULL;
 51         int uplink = 0;
 52         int downlinks[32] = {0};
 53         size_t downlinks_cnt = 0;
 54         enum proxy_flags flags = 0;
 55 
 56         if (!name)
 57                 return -EINVAL;
 58 
 59         if (!(uplink = if_nametoindex(name))) {
 60                 L_WARN("%s(%s): %s", __FUNCTION__, name, strerror(errno));
 61                 return -errno;
 62         }
 63 
 64         if ((c = tb[PROXY_ATTR_SCOPE])) {
 65                 const char *scope = blobmsg_get_string(c);
 66                 if (!strcmp(scope, "global"))
 67                         flags = PROXY_GLOBAL;
 68                 else if (!strcmp(scope, "organization"))
 69                         flags = PROXY_ORGLOCAL;
 70                 else if (!strcmp(scope, "site"))
 71                         flags = PROXY_SITELOCAL;
 72                 else if (!strcmp(scope, "admin"))
 73                         flags = PROXY_ADMINLOCAL;
 74                 else if (!strcmp(scope, "realm"))
 75                         flags = PROXY_REALMLOCAL;
 76 
 77                 if (!flags) {
 78                         L_WARN("%s(%s): invalid scope (%s)", __FUNCTION__, name, scope);
 79                         return -EINVAL;
 80                 }
 81         }
 82 
 83         if ((c = tb[PROXY_ATTR_DEST])) {
 84                 struct blob_attr *d;
 85                 unsigned rem;
 86                 blobmsg_for_each_attr(d, c, rem) {
 87                         if (downlinks_cnt >= 32) {
 88                                 L_WARN("%s(%s): maximum number of destinations exceeded", __FUNCTION__, name);
 89                                 return -EINVAL;
 90                         }
 91 
 92                         const char *n = blobmsg_type(d) == BLOBMSG_TYPE_STRING ? blobmsg_get_string(d) : "";
 93                         if (!(downlinks[downlinks_cnt++] = if_nametoindex(n))) {
 94                                 L_WARN("%s(%s): %s (%s)", __FUNCTION__, name, strerror(errno), blobmsg_get_string(d));
 95                                 return -errno;
 96                         }
 97                 }
 98         }
 99 
100         return proxy_set(uplink, downlinks, downlinks_cnt, flags, opts);
101 }
102 
103 // Parse a positive integer option value
104 static bool option_int(const char *value, long max, long *out)
105 {
106         char *end;
107         long v = strtol(value, &end, 10);
108         if (*value == '\0' || *end != '\0' || v <= 0 || v > max)
109                 return false;
110         *out = v;
111         return true;
112 }
113 
114 // Parse an altnet=<prefix> value into a v4-mapped or IPv6 prefix
115 static bool option_altnet(const char *value, struct proxy_options *opts)
116 {
117         char buf[INET6_ADDRSTRLEN + 4];
118         struct proxy_altnet *net;
119         char *slash, *end;
120         struct in_addr a4;
121         long plen;
122 
123         if (opts->altnets_cnt >= PROXY_MAX_ALTNETS || strlen(value) >= sizeof(buf))
124                 return false;
125 
126         strcpy(buf, value);
127         if (!(slash = strchr(buf, '/')))
128                 return false;
129         *slash++ = '\0';
130         plen = strtol(slash, &end, 10);
131         if (*slash == '\0' || *end != '\0' || plen < 0)
132                 return false;
133 
134         net = &opts->altnets[opts->altnets_cnt];
135         if (inet_pton(AF_INET, buf, &a4) == 1 && plen <= 32) {
136                 memset(&net->addr, 0, sizeof(net->addr));
137                 net->addr.s6_addr[10] = 0xff;
138                 net->addr.s6_addr[11] = 0xff;
139                 memcpy(&net->addr.s6_addr[12], &a4, sizeof(a4));
140                 net->plen = (uint8_t)(96 + plen);
141         } else if (inet_pton(AF_INET6, buf, &net->addr) == 1 && plen <= 128) {
142                 net->plen = (uint8_t)plen;
143         } else {
144                 return false;
145         }
146 
147         opts->altnets_cnt++;
148         return true;
149 }
150 
151 // Parse one proxy option; false for an unknown or invalid option
152 static bool option_parse(const char *c, struct proxy_options *opts)
153 {
154         struct querier_config *q = &opts->querier;
155         long v;
156 
157         if (!strcmp(c, "fast_leave")) {
158                 q->fast_leave = true;
159                 return true;
160         }
161         if (!strncmp(c, "robustness=", 11) && option_int(&c[11], 255, &v)) {
162                 q->robustness = (int)v;
163                 return true;
164         }
165         if (!strncmp(c, "query_interval=", 15) && option_int(&c[15], 31744, &v)) {
166                 q->query_interval = v * OMGP_TIME_PER_SECOND;
167                 return true;
168         }
169         if (!strncmp(c, "query_response_interval=", 24) && option_int(&c[24], 31744, &v)) {
170                 q->query_response_interval = v * OMGP_TIME_PER_SECOND / 10;
171                 return true;
172         }
173         if (!strncmp(c, "last_member_query_interval=", 27) && option_int(&c[27], 31744, &v)) {
174                 q->last_member_query_interval = v * OMGP_TIME_PER_SECOND / 10;
175                 return true;
176         }
177         if (!strncmp(c, "altnet=", 7))
178                 return option_altnet(&c[7], opts);
179 
180         return false;
181 }
182 
183 static void handle_signal(__unused int signal)
184 {
185         uloop_end();
186 }
187 
188 static void usage(const char *arg) {
189         fprintf(stderr, "Usage: %s [options] <proxy1> [<proxy2>] [...]\n"
190                         "\nProxy examples:\n"
191                         "eth1,eth2\n"
192                         "eth1,eth2,eth3,scope=organization\n"
193                         "\nProxy options (each option may only occur once):\n"
194                         "       <interface>                     interfaces to proxy (first is uplink)\n"
195                         "       scope=<scope>                   minimum multicast scope to proxy\n"
196                         "               [global,organization,site,admin,realm] (default: global)\n"
197                         "       robustness=<n>                  querier robustness variable (default: 2)\n"
198                         "       query_interval=<s>              general query interval in seconds (default: 125)\n"
199                         "       query_response_interval=<ds>    maximum response delay in tenths of a second (default: 100)\n"
200                         "       last_member_query_interval=<ds> last member query interval in tenths of a second (default: 10)\n"
201                         "       fast_leave                      end a group or source at once on a leave\n"
202                         "       altnet=<prefix>                 route only sources in these networks (may repeat;\n"
203                         "                                       default: all sources of the family)\n"
204                         "\nOptions:\n"
205                         "       -v                              verbose logging\n"
206                         "       -h                              show this help\n",
207         arg);
208 }
209 
210 int main(int argc, char **argv) {
211         signal(SIGINT, handle_signal);
212         signal(SIGTERM, handle_signal);
213         signal(SIGHUP, SIG_IGN);
214         signal(SIGPIPE, SIG_IGN);
215         openlog("omcproxy", LOG_PERROR | LOG_PID, LOG_DAEMON);
216         setlogmask(LOG_UPTO(L_LEVEL));
217 
218         if (getuid()) {
219                 L_ERR("must be run as root!");
220                 return 2;
221         }
222 
223         uloop_init();
224         bool start = true;
225 
226         for (ssize_t i = 1; i < argc; ++i) {
227                 const char *source = NULL;
228                 const char *scope = NULL;
229                 struct proxy_options opts;
230                 struct blob_buf b = {NULL, NULL, 0, NULL};
231 
232                 memset(&opts, 0, sizeof(opts));
233 
234                 if (!strcmp(argv[i], "-h")) {
235                         usage(argv[0]);
236                         return 1;
237                 } else if (!strncmp(argv[i], "-v", 2)) {
238                         int log_level;
239                         if ((log_level = atoi(&argv[i][2])) <= 0)
240                                 log_level = LOG_DEBUG;
241                         setlogmask(LOG_UPTO(log_level));
242                         continue;
243                 }
244 
245 
246                 blob_buf_init(&b, 0);
247 
248                 void *k = blobmsg_open_array(&b, "dest");
249                 for (char *c = strtok(argv[i], ","); c; c = strtok(NULL, ",")) {
250                         if (!strncmp(c, "scope=", 6)) {
251                                 scope = &c[6];
252                         } else if (strchr(c, '=') || !strcmp(c, "fast_leave")) {
253                                 if (!option_parse(c, &opts)) {
254                                         fprintf(stderr, "invalid proxy option: %s\n", c);
255                                         start = false;
256                                 }
257                         } else if (!source) {
258                                 source = c;
259                         } else {
260                                 blobmsg_add_string(&b, NULL, c);
261                         }
262                 }
263                 blobmsg_close_array(&b, k);
264 
265                 if (source)
266                         blobmsg_add_string(&b, "source", source);
267 
268                 if (scope)
269                         blobmsg_add_string(&b, "scope", scope);
270 
271                 if (handle_proxy_set(blob_data(b.head), blob_len(b.head), &opts)) {
272                         fprintf(stderr, "failed to setup proxy: %s\n", argv[i]);
273                         start = false;
274                 }
275 
276                 blob_buf_free(&b);
277         }
278 
279         if (argc < 2) {
280                 usage(argv[0]);
281                 start = false;
282         }
283 
284         if (start)
285                 uloop_run();
286 
287         proxy_update(true);
288         proxy_flush();
289 
290         uloop_done();
291         return 0;
292 }
293 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt