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