/* * Copyright 2015 Steven Barth * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include #include #include #include #include #include #include #include "omcproxy.h" #include "proxy.h" enum { PROXY_ATTR_SOURCE, PROXY_ATTR_SCOPE, PROXY_ATTR_DEST, PROXY_ATTR_MAX, }; static struct blobmsg_policy proxy_policy[PROXY_ATTR_MAX] = { [PROXY_ATTR_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING }, [PROXY_ATTR_SCOPE] = { .name = "scope", .type = BLOBMSG_TYPE_STRING }, [PROXY_ATTR_DEST] = { .name = "dest", .type = BLOBMSG_TYPE_ARRAY }, }; static int handle_proxy_set(void *data, size_t len) { struct blob_attr *tb[PROXY_ATTR_MAX], *c; blobmsg_parse(proxy_policy, PROXY_ATTR_MAX, tb, data, len); const char *name = ((c = tb[PROXY_ATTR_SOURCE])) ? blobmsg_get_string(c) : NULL; int uplink = 0; int downlinks[32] = {0}; size_t downlinks_cnt = 0; enum proxy_flags flags = 0; if (!name) return -EINVAL; if (!(uplink = if_nametoindex(name))) { L_WARN("%s(%s): %s", __FUNCTION__, name, strerror(errno)); return -errno; } if ((c = tb[PROXY_ATTR_SCOPE])) { const char *scope = blobmsg_get_string(c); if (!strcmp(scope, "global")) flags = PROXY_GLOBAL; else if (!strcmp(scope, "organization")) flags = PROXY_ORGLOCAL; else if (!strcmp(scope, "site")) flags = PROXY_SITELOCAL; else if (!strcmp(scope, "admin")) flags = PROXY_ADMINLOCAL; else if (!strcmp(scope, "realm")) flags = PROXY_REALMLOCAL; if (!flags) { L_WARN("%s(%s): invalid scope (%s)", __FUNCTION__, name, scope); return -EINVAL; } } if ((c = tb[PROXY_ATTR_DEST])) { struct blob_attr *d; unsigned rem; blobmsg_for_each_attr(d, c, rem) { if (downlinks_cnt >= 32) { L_WARN("%s(%s): maximum number of destinations exceeded", __FUNCTION__, name); return -EINVAL; } const char *n = blobmsg_type(d) == BLOBMSG_TYPE_STRING ? blobmsg_get_string(d) : ""; if (!(downlinks[downlinks_cnt++] = if_nametoindex(n))) { L_WARN("%s(%s): %s (%s)", __FUNCTION__, name, strerror(errno), blobmsg_get_string(d)); return -errno; } } } return proxy_set(uplink, downlinks, downlinks_cnt, flags); } static void handle_signal(__unused int signal) { uloop_end(); } static void usage(const char *arg) { fprintf(stderr, "Usage: %s [options] [] [...]\n" "\nProxy examples:\n" "eth1,eth2\n" "eth1,eth2,eth3,scope=organization\n" "\nProxy options (each option may only occur once):\n" " interfaces to proxy (first is uplink)\n" " scope= minimum multicast scope to proxy\n" " [global,organization,site,admin,realm] (default: global)\n" "\nOptions:\n" " -v verbose logging\n" " -h show this help\n", arg); } int main(int argc, char **argv) { signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); openlog("omcproxy", LOG_PERROR | LOG_PID, LOG_DAEMON); setlogmask(LOG_UPTO(L_LEVEL)); if (getuid()) { L_ERR("must be run as root!"); return 2; } uloop_init(); bool start = true; for (ssize_t i = 1; i < argc; ++i) { const char *source = NULL; const char *scope = NULL; struct blob_buf b = {NULL, NULL, 0, NULL}; if (!strcmp(argv[i], "-h")) { usage(argv[0]); return 1; } else if (!strncmp(argv[i], "-v", 2)) { int log_level; if ((log_level = atoi(&argv[i][2])) <= 0) log_level = LOG_DEBUG; setlogmask(LOG_UPTO(log_level)); continue; } blob_buf_init(&b, 0); void *k = blobmsg_open_array(&b, "dest"); for (char *c = strtok(argv[i], ","); c; c = strtok(NULL, ",")) { if (!strncmp(c, "scope=", 6)) { scope = &c[6]; } else if (!source) { source = c; } else { blobmsg_add_string(&b, NULL, c); } } blobmsg_close_array(&b, k); if (source) blobmsg_add_string(&b, "source", source); if (scope) blobmsg_add_string(&b, "scope", scope); if (handle_proxy_set(blob_data(b.head), blob_len(b.head))) { fprintf(stderr, "failed to setup proxy: %s\n", argv[i]); start = false; } blob_buf_free(&b); } if (argc < 2) { usage(argv[0]); start = false; } if (start) uloop_run(); proxy_update(true); proxy_flush(); uloop_done(); return 0; }