1
/* -*- coding: utf-8 -*- */
3
* iprouteadddel - Add or delete direct route to a local IP address
5
* Copyright © 2015-2018 Teddy Hogeborn
6
* Copyright © 2015-2018 Björn Påhlsson
8
* This file is part of Mandos.
10
* Mandos is free software: you can redistribute it and/or modify it
11
* under the terms of the GNU General Public License as published by
12
* the Free Software Foundation, either version 3 of the License, or
13
* (at your option) any later version.
15
* Mandos is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Mandos. If not, see <http://www.gnu.org/licenses/>.
23
* Contact the authors at <mandos@recompile.se>.
26
#define _GNU_SOURCE /* program_invocation_short_name */
27
#include <stdbool.h> /* bool, false, true */
28
#include <argp.h> /* argp_program_version,
29
argp_program_bug_address,
31
struct argp_state, ARGP_KEY_ARG,
32
argp_usage(), ARGP_KEY_END,
33
ARGP_ERR_UNKNOWN, struct argp,
34
argp_parse(), ARGP_IN_ORDER */
35
#include <errno.h> /* errno,
36
program_invocation_short_name,
37
error_t, EINVAL, ENOMEM */
38
#include <stdio.h> /* fprintf(), stderr, perror(), FILE,
40
#include <stdarg.h> /* va_list, va_start(), vfprintf() */
41
#include <stdlib.h> /* EXIT_SUCCESS */
42
#include <netlink/netlink.h> /* struct nl_addr, nl_addr_parse(),
44
nl_addr_get_family(), NLM_F_EXCL,
46
#include <stddef.h> /* NULL */
47
#include <netlink/route/route.h>/* struct rtnl_route,
48
struct rtnl_nexthop, NETLINK_ROUTE,
50
rtnl_route_set_family(),
51
rtnl_route_set_protocol(),
53
rtnl_route_set_scope(),
55
rtnl_route_set_type(), RTN_UNICAST,
57
rtnl_route_set_table(),
59
rtnl_route_nh_alloc(),
60
rtnl_route_nh_set_ifindex(),
61
rtnl_route_add_nexthop(),
65
rtnl_route_nh_free() */
66
#include <netlink/socket.h> /* struct nl_sock, nl_socket_alloc(),
67
nl_connect(), nl_socket_free() */
68
#include <strings.h> /* strcasecmp() */
69
#include <sys/socket.h> /* AF_UNSPEC, AF_INET6, AF_INET */
70
#include <sysexits.h> /* EX_USAGE, EX_OSERR */
71
#include <netlink/route/link.h> /* struct rtnl_link,
72
rtnl_link_get_kernel(),
73
rtnl_link_get_ifindex(),
75
#include <netinet/in.h> /* sa_family_t */
76
#include <inttypes.h> /* PRIdMAX, intmax_t */
77
#include <stdint.h> /* uint8_t */
81
const char *argp_program_version = "mandos-client-iprouteadddel " VERSION;
82
const char *argp_program_bug_address = "<mandos@recompile.se>";
84
/* Function to use when printing errors */
85
void perror_plus(const char *print_text){
87
fprintf(stderr, "Mandos plugin helper %s: ",
88
program_invocation_short_name);
93
__attribute__((format (gnu_printf, 2, 3), nonnull))
94
int fprintf_plus(FILE *stream, const char *format, ...){
96
va_start (ap, format);
98
fprintf(stream, "Mandos plugin helper %s: ",
99
program_invocation_short_name);
100
return vfprintf(stream, format, ap);
103
int main(int argc, char *argv[]){
105
int exitcode = EXIT_SUCCESS;
107
bool add; /* true: add, false: delete */
108
char *address; /* IP address as string */
109
struct nl_addr *nl_addr; /* Netlink IP address */
110
char *interface; /* interface name */
111
} arguments = { .add = true, .address = NULL, .interface = NULL };
112
struct argp_option options[] = {
113
{ .name = "debug", .key = 128,
114
.doc = "Debug mode" },
117
struct rtnl_route *route = NULL;
118
struct rtnl_nexthop *nexthop = NULL;
119
struct nl_sock *sk = NULL;
121
error_t parse_opt(int key, char *arg, struct argp_state *state){
125
case 128: /* --debug */
129
switch(state->arg_num){
131
if(strcasecmp(arg, "add") == 0){
132
((struct arguments *)(state->input))->add = true;
133
} else if(strcasecmp(arg, "delete") == 0){
134
((struct arguments *)(state->input))->add = false;
136
fprintf_plus(stderr, "Unrecognized command: %s\n", arg);
141
((struct arguments *)(state->input))->address = arg;
142
lret = nl_addr_parse(arg, AF_UNSPEC, &(((struct arguments *)
146
fprintf_plus(stderr, "Failed to parse address %s: %s\n",
147
arg, nl_geterror(lret));
152
((struct arguments *)(state->input))->interface = arg;
159
if(state->arg_num < 3){
164
return ARGP_ERR_UNKNOWN;
169
struct argp argp = { .options = options, .parser = parse_opt,
170
.args_doc = "[ add | delete ] ADDRESS INTERFACE",
171
.doc = "Mandos client helper -- Add or delete"
172
" local route to IP address on interface" };
174
ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &arguments);
183
perror_plus("argp_parse");
187
/* Get netlink socket */
188
sk = nl_socket_alloc();
190
fprintf_plus(stderr, "Failed to allocate netlink socket: %s\n",
195
/* Connect socket to netlink */
196
ret = nl_connect(sk, NETLINK_ROUTE);
198
fprintf_plus(stderr, "Failed to connect socket to netlink: %s\n",
203
/* Get link object of specified interface */
204
struct rtnl_link *link = NULL;
205
ret = rtnl_link_get_kernel(sk, 0, arguments.interface, &link);
207
fprintf_plus(stderr, "Failed to use interface %s: %s\n",
208
arguments.interface, nl_geterror(ret));
212
/* Get netlink route object */
213
route = rtnl_route_alloc();
215
fprintf_plus(stderr, "Failed to get netlink route:\n");
219
/* Get address family of specified address */
220
sa_family_t af = (sa_family_t)nl_addr_get_family(arguments.nl_addr);
222
fprintf_plus(stderr, "Address family of %s is %s (%" PRIdMAX
223
")\n", arguments.address,
224
af == AF_INET6 ? "AF_INET6" :
225
( af == AF_INET ? "AF_INET" : "UNKNOWN"),
228
/* Set route parameters: */
229
rtnl_route_set_family(route, (uint8_t)af); /* Address family */
230
rtnl_route_set_protocol(route, RTPROT_BOOT); /* protocol - see
232
rtnl_route_set_scope(route, RT_SCOPE_LINK); /* link scope */
233
rtnl_route_set_type(route, RTN_UNICAST); /* normal unicast
235
rtnl_route_set_dst(route, arguments.nl_addr); /* Destination
237
rtnl_route_set_table(route, RT_TABLE_MAIN); /* "main" routing
240
nexthop = rtnl_route_nh_alloc();
242
fprintf_plus(stderr, "Failed to get netlink route nexthop\n");
246
/* Get index number of specified interface */
247
int ifindex = rtnl_link_get_ifindex(link);
249
fprintf_plus(stderr, "ifindex of %s is %d\n", arguments.interface,
252
/* Set interface index number on nexthop object */
253
rtnl_route_nh_set_ifindex(nexthop, ifindex);
254
/* Set route to use nexthop object */
255
rtnl_route_add_nexthop(route, nexthop);
256
/* Add or delete route? */
258
ret = rtnl_route_add(sk, route, NLM_F_EXCL);
260
ret = rtnl_route_delete(sk, route, 0);
263
fprintf_plus(stderr, "Failed to %s route: %s\n",
264
arguments.add ? "add" : "delete",
270
/* Deallocate route */
272
rtnl_route_put(route);
274
/* Deallocate route nexthop */
275
rtnl_route_nh_free(nexthop);
277
/* Deallocate parsed address */
278
if(arguments.nl_addr){
279
nl_addr_put(arguments.nl_addr);
281
/* Deallocate link struct */
285
/* Deallocate netlink socket struct */