1
/* -*- coding: utf-8 -*- */
3
* iprouteadddel - Add or delete direct route to a local IP address
5
* Copyright © 2015 Teddy Hogeborn
6
* Copyright © 2015 Björn Påhlsson
8
* This program is free software: you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License as
10
* published by the Free Software Foundation, either version 3 of the
11
* License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see
20
* <http://www.gnu.org/licenses/>.
22
* Contact the authors at <mandos@recompile.se>.
25
#define _GNU_SOURCE /* asprintf(),
26
program_invocation_short_name */
27
#include <iso646.h> /* not, or, and */
28
#include <stdbool.h> /* bool, false, true */
29
#include <stdio.h> /* vfprintf(), stderr, stdout */
30
#include <stdarg.h> /* va_list, va_start */
31
#include <errno.h> /* perror(), errno,
32
program_invocation_short_name */
33
#include <argp.h> /* struct argp_option, error_t, struct
34
argp_state, struct argp,
35
argp_parse(), ARGP_KEY_ARG,
36
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
37
#include <inttypes.h> /* PRIdMAX, intmax_t */
38
#include <sysexits.h> /* EX_OSERR */
40
/* #include <linux/netlink.h> */
41
/* #include <netlink/netlink.h> */
42
/* #include <netlink/socket.h> */
43
#include <netlink/netlink.h>
44
#include <netlink/socket.h>
45
#include <netlink/cache.h>
46
#include <netlink/route/link.h> /* libnl xxx */
47
#include <netlink/route/route.h> /* libnl xxx */
50
const char *argp_program_version = "mandos-client-iprouteadddel " VERSION;
51
const char *argp_program_bug_address = "<mandos@recompile.se>";
53
/* Function to use when printing errors */
54
void perror_plus(const char *print_text){
56
fprintf(stderr, "Mandos plugin helper %s: ",
57
program_invocation_short_name);
62
__attribute__((format (gnu_printf, 2, 3), nonnull))
63
int fprintf_plus(FILE *stream, const char *format, ...){
65
va_start (ap, format);
67
fprintf(stream, "Mandos plugin helper %s: ",
68
program_invocation_short_name);
69
return vfprintf(stream, format, ap);
72
int main(int argc, char *argv[]){
74
int exitcode = EXIT_SUCCESS;
76
bool add; /* true: add, false: delete */
77
char *address; /* IP address as string */
78
struct nl_addr *nl_addr; /* Netlink IP address */
79
char *interface; /* interface name */
80
} arguments = { .add = true, .address = NULL, .interface = NULL };
81
struct argp_option options[] = {
82
{ .name = "debug", .key = 128,
83
.doc = "Debug mode" },
86
struct rtnl_route *route = NULL;
87
struct rtnl_nexthop *nexthop = NULL;
88
struct nl_sock *sk = NULL;
90
error_t parse_opt(int key, char *arg, struct argp_state *state){
94
case 128: /* --debug */
98
switch(state->arg_num){
100
if(strcasecmp(arg, "add") == 0){
101
((struct arguments *)(state->input))->add = true;
102
} else if(strcasecmp(arg, "delete") == 0){
103
((struct arguments *)(state->input))->add = false;
105
fprintf_plus(stderr, "Unrecognized command: %s\n", arg);
110
((struct arguments *)(state->input))->address = arg;
111
lret = nl_addr_parse(arg, AF_UNSPEC, &(((struct arguments *)
115
fprintf_plus(stderr, "Failed to parse address %s: %s\n",
116
arg, nl_geterror(lret));
121
((struct arguments *)(state->input))->interface = arg;
128
if(state->arg_num < 3){
133
return ARGP_ERR_UNKNOWN;
138
struct argp argp = { .options = options, .parser = parse_opt,
139
.args_doc = "[ add | delete ] ADDRESS INTERFACE",
140
.doc = "Mandos client helper -- Add or delete"
141
" local route to IP address on interface" };
143
ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &arguments);
152
perror_plus("argp_parse");
156
/* Get netlink socket */
157
sk = nl_socket_alloc();
159
fprintf_plus(stderr, "Failed to allocate netlink socket: %s\n",
164
/* Connect socket to netlink */
165
ret = nl_connect(sk, NETLINK_ROUTE);
167
fprintf_plus(stderr, "Failed to connect socket to netlink: %s\n",
172
/* Get link object of specified interface */
173
struct rtnl_link *link = NULL;
174
ret = rtnl_link_get_kernel(sk, 0, arguments.interface, &link);
176
fprintf_plus(stderr, "Failed to use interface %s: %s\n",
177
arguments.interface, nl_geterror(ret));
181
/* Get netlink route object */
182
route = rtnl_route_alloc();
184
fprintf_plus(stderr, "Failed to get netlink route:\n");
188
/* Get address family of specified address */
189
sa_family_t af = (sa_family_t)nl_addr_get_family(arguments.nl_addr);
191
fprintf_plus(stderr, "Address family of %s is %s (%" PRIdMAX
192
")\n", arguments.address,
193
af == AF_INET6 ? "AF_INET6" :
194
( af == AF_INET ? "AF_INET" : "UNKNOWN"),
197
/* Set route parameters: */
198
rtnl_route_set_family(route, (uint8_t)af); /* Address family */
199
rtnl_route_set_protocol(route, RTPROT_BOOT); /* protocol - see
201
rtnl_route_set_scope(route, RT_SCOPE_LINK); /* link scope */
202
rtnl_route_set_type(route, RTN_UNICAST); /* normal unicast
204
rtnl_route_set_dst(route, arguments.nl_addr); /* Destination
206
rtnl_route_set_table(route, RT_TABLE_MAIN); /* "main" routing
209
nexthop = rtnl_route_nh_alloc();
211
fprintf_plus(stderr, "Failed to get netlink route nexthop:\n");
215
/* Get index number of specified interface */
216
int ifindex = rtnl_link_get_ifindex(link);
218
fprintf_plus(stderr, "ifindex of %s is %d\n", arguments.interface,
221
/* Set interface index number on nexthop object */
222
rtnl_route_nh_set_ifindex(nexthop, ifindex);
223
/* Set route tu use nexthop object */
224
rtnl_route_add_nexthop(route, nexthop);
225
/* Add or delete route? */
227
ret = rtnl_route_add(sk, route, NLM_F_EXCL);
229
ret = rtnl_route_delete(sk, route, 0);
232
fprintf_plus(stderr, "Failed to %s route: %s\n",
233
arguments.add ? "add" : "delete",
239
/* Deallocate route */
241
rtnl_route_put(route);
243
/* Deallocate route nexthop */
244
rtnl_route_nh_free(nexthop);
246
/* Deallocate parsed address */
247
if(arguments.nl_addr){
248
nl_addr_put(arguments.nl_addr);
250
/* Deallocate link struct */
254
/* Deallocate netlink socket struct */