2 * Copyright 2015 Steven Barth <steven at midlink.org>
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <libubox/uloop.h>
27 #include <libubox/blobmsg.h>
32 int log_level
= LOG_WARNING
;
42 static struct blobmsg_policy proxy_policy
[PROXY_ATTR_MAX
] = {
43 [PROXY_ATTR_SOURCE
] = { .name
= "source", .type
= BLOBMSG_TYPE_STRING
},
44 [PROXY_ATTR_SCOPE
] = { .name
= "scope", .type
= BLOBMSG_TYPE_STRING
},
45 [PROXY_ATTR_DEST
] = { .name
= "dest", .type
= BLOBMSG_TYPE_ARRAY
},
48 static int handle_proxy_set(void *data
, size_t len
)
50 struct blob_attr
*tb
[PROXY_ATTR_MAX
], *c
;
51 blobmsg_parse(proxy_policy
, PROXY_ATTR_MAX
, tb
, data
, len
);
53 const char *name
= ((c
= tb
[PROXY_ATTR_SOURCE
])) ? blobmsg_get_string(c
) : NULL
;
55 int downlinks
[32] = {0};
56 size_t downlinks_cnt
= 0;
57 enum proxy_flags flags
= 0;
62 if (!(uplink
= if_nametoindex(name
))) {
63 L_WARN("%s(%s): %s", __FUNCTION__
, name
, strerror(errno
));
67 if ((c
= tb
[PROXY_ATTR_SCOPE
])) {
68 const char *scope
= blobmsg_get_string(c
);
69 if (!strcmp(scope
, "global"))
71 else if (!strcmp(scope
, "organization"))
72 flags
= PROXY_ORGLOCAL
;
73 else if (!strcmp(scope
, "site"))
74 flags
= PROXY_SITELOCAL
;
75 else if (!strcmp(scope
, "admin"))
76 flags
= PROXY_ADMINLOCAL
;
77 else if (!strcmp(scope
, "realm"))
78 flags
= PROXY_REALMLOCAL
;
81 L_WARN("%s(%s): invalid scope (%s)", __FUNCTION__
, name
, scope
);
86 if ((c
= tb
[PROXY_ATTR_DEST
])) {
89 blobmsg_for_each_attr(d
, c
, rem
) {
90 if (downlinks_cnt
>= 32) {
91 L_WARN("%s(%s): maximum number of destinations exceeded", __FUNCTION__
, name
);
95 const char *n
= blobmsg_type(d
) == BLOBMSG_TYPE_STRING
? blobmsg_get_string(d
) : "";
96 if (!(downlinks
[downlinks_cnt
++] = if_nametoindex(n
))) {
97 L_WARN("%s(%s): %s (%s)", __FUNCTION__
, name
, strerror(errno
), blobmsg_get_string(d
));
103 return proxy_set(uplink
, downlinks
, downlinks_cnt
, flags
);
106 static void handle_signal(__unused
int signal
)
111 static void usage(const char *arg
) {
112 fprintf(stderr
, "Usage: %s [options] <proxy1> [<proxy2>] [...]\n"
113 "\nProxy examples:\n"
115 "eth1,eth2,eth3,scope=organization\n"
116 "\nProxy options (each option may only occur once):\n"
117 " <interface> interfaces to proxy (first is uplink)\n"
118 " scope=<scope> minimum multicast scope to proxy\n"
119 " [global,organization,site,admin,realm] (default: global)\n"
121 " -v verbose logging\n"
122 " -h show this help\n",
126 int main(int argc
, char **argv
) {
127 signal(SIGINT
, handle_signal
);
128 signal(SIGTERM
, handle_signal
);
129 signal(SIGHUP
, SIG_IGN
);
130 signal(SIGPIPE
, SIG_IGN
);
131 openlog("omcproxy", LOG_PERROR
, LOG_DAEMON
);
134 L_ERR("must be run as root!");
141 for (ssize_t i
= 1; i
< argc
; ++i
) {
142 const char *source
= NULL
;
143 const char *scope
= NULL
;
144 struct blob_buf b
= {NULL
, NULL
, 0, NULL
};
146 if (!strcmp(argv
[i
], "-h")) {
149 } else if (!strncmp(argv
[i
], "-v", 2)) {
150 if ((log_level
= atoi(&argv
[i
][2])) <= 0)
156 blob_buf_init(&b
, 0);
158 void *k
= blobmsg_open_array(&b
, "dest");
159 for (char *c
= strtok(argv
[i
], ","); c
; c
= strtok(NULL
, ",")) {
160 if (!strncmp(c
, "scope=", 6)) {
162 } else if (!source
) {
165 blobmsg_add_string(&b
, NULL
, c
);
168 blobmsg_close_array(&b
, k
);
171 blobmsg_add_string(&b
, "source", source
);
174 blobmsg_add_string(&b
, "scope", scope
);
176 if (handle_proxy_set(blob_data(b
.head
), blob_len(b
.head
))) {
177 fprintf(stderr
, "failed to setup proxy: %s\n", argv
[i
]);