/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugin-helpers/mandos-client-iprouteadddel.c

  • Committer: Teddy Hogeborn
  • Date: 2011-12-31 20:07:11 UTC
  • mfrom: (535.1.9 wireless-network-hook)
  • Revision ID: teddy@recompile.se-20111231200711-6dli3r8drftem57r
Merge new wireless network hook.  Fix bridge network hook to use
hardware addresses instead of interface names.  Implement and document
new "CONNECT" environment variable for network hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/* 
3
 
 * iprouteadddel - Add or delete direct route to a local IP address
4
 
 * 
5
 
 * Copyright © 2015-2017 Teddy Hogeborn
6
 
 * Copyright © 2015-2017 Björn Påhlsson
7
 
 * 
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.
12
 
 * 
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.
17
 
 * 
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/>.
21
 
 * 
22
 
 * Contact the authors at <mandos@recompile.se>.
23
 
 */
24
 
 
25
 
#define _GNU_SOURCE             /* asprintf(),
26
 
                                   program_invocation_short_name */
27
 
#include <stdbool.h>            /* bool, false, true */
28
 
#include <stdio.h>              /* fprintf(), stderr, FILE, vfprintf */
29
 
#include <errno.h>              /* program_invocation_short_name,
30
 
                                   errno, perror(), EINVAL, ENOMEM */
31
 
#include <stdarg.h>             /* va_list, va_start */
32
 
#include <stdlib.h>             /* EXIT_SUCCESS */
33
 
#include <argp.h>               /* struct argp_option, error_t, struct
34
 
                                   argp_state, ARGP_KEY_ARG,
35
 
                                   argp_usage(), ARGP_KEY_END,
36
 
                                   ARGP_ERR_UNKNOWN, struct argp,
37
 
                                   argp_parse() */
38
 
#include <sysexits.h>           /* EX_USAGE, EX_OSERR */
39
 
#include <netinet/ip.h>         /* sa_family_t, AF_INET6, AF_INET */
40
 
#include <inttypes.h>           /* PRIdMAX, intmax_t */
41
 
 
42
 
#include <netlink/netlink.h>    /* struct nl_addr, nl_addr_parse(),
43
 
                                   nl_geterror(),
44
 
                                   nl_addr_get_family(),
45
 
                                   nl_addr_put() */
46
 
#include <netlink/route/route.h> /* struct rtnl_route,
47
 
                                    struct rtnl_nexthop,
48
 
                                    rtnl_route_alloc(),
49
 
                                    rtnl_route_set_family(),
50
 
                                    rtnl_route_set_protocol(),
51
 
                                    RTPROT_BOOT,
52
 
                                    rtnl_route_set_scope(),
53
 
                                    RT_SCOPE_LINK,
54
 
                                    rtnl_route_set_type(),
55
 
                                    RTN_UNICAST,
56
 
                                    rtnl_route_set_dst(),
57
 
                                    rtnl_route_set_table(),
58
 
                                    RT_TABLE_MAIN,
59
 
                                    rtnl_route_nh_alloc(),
60
 
                                    rtnl_route_nh_set_ifindex(),
61
 
                                    rtnl_route_add_nexthop(),
62
 
                                    rtnl_route_add(),
63
 
                                    rtnl_route_delete(),
64
 
                                    rtnl_route_put(),
65
 
                                    rtnl_route_nh_free() */
66
 
#include <netlink/socket.h>     /* struct nl_sock, nl_socket_alloc(),
67
 
                                   nl_connect(), nl_socket_free() */
68
 
#include <netlink/route/link.h> /* rtnl_link_get_kernel(),
69
 
                                   rtnl_link_get_ifindex(),
70
 
                                   rtnl_link_put() */
71
 
 
72
 
bool debug = false;
73
 
const char *argp_program_version = "mandos-client-iprouteadddel " VERSION;
74
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
75
 
 
76
 
/* Function to use when printing errors */
77
 
void perror_plus(const char *print_text){
78
 
  int e = errno;
79
 
  fprintf(stderr, "Mandos plugin helper %s: ",
80
 
          program_invocation_short_name);
81
 
  errno = e;
82
 
  perror(print_text);
83
 
}
84
 
 
85
 
__attribute__((format (gnu_printf, 2, 3), nonnull))
86
 
int fprintf_plus(FILE *stream, const char *format, ...){
87
 
  va_list ap;
88
 
  va_start (ap, format);
89
 
  
90
 
  fprintf(stream, "Mandos plugin helper %s: ",
91
 
          program_invocation_short_name);
92
 
  return vfprintf(stream, format, ap);
93
 
}
94
 
 
95
 
int main(int argc, char *argv[]){
96
 
  int ret;
97
 
  int exitcode = EXIT_SUCCESS;
98
 
  struct arguments {
99
 
    bool add;                   /* true: add, false: delete */
100
 
    char *address;              /* IP address as string */
101
 
    struct nl_addr *nl_addr;    /* Netlink IP address */
102
 
    char *interface;            /* interface name */
103
 
  } arguments = { .add = true, .address = NULL, .interface = NULL };
104
 
  struct argp_option options[] = {
105
 
    { .name = "debug", .key = 128,
106
 
      .doc = "Debug mode" },
107
 
    { .name = NULL }
108
 
  };
109
 
  struct rtnl_route *route = NULL;
110
 
  struct rtnl_nexthop *nexthop = NULL;
111
 
  struct nl_sock *sk = NULL;
112
 
  
113
 
  error_t parse_opt(int key, char *arg, struct argp_state *state){
114
 
    int lret;
115
 
    errno = 0;
116
 
    switch(key){
117
 
    case 128:                   /* --debug */
118
 
      debug = true;
119
 
      break;
120
 
    case ARGP_KEY_ARG:
121
 
      switch(state->arg_num){
122
 
      case 0:
123
 
        if(strcasecmp(arg, "add") == 0){
124
 
          ((struct arguments *)(state->input))->add = true;
125
 
        } else if(strcasecmp(arg, "delete") == 0){
126
 
          ((struct arguments *)(state->input))->add = false;
127
 
        } else {
128
 
          fprintf_plus(stderr, "Unrecognized command: %s\n", arg);
129
 
          argp_usage(state);
130
 
        }
131
 
        break;
132
 
      case 1:
133
 
        ((struct arguments *)(state->input))->address = arg;
134
 
        lret = nl_addr_parse(arg, AF_UNSPEC, &(((struct arguments *)
135
 
                                                (state->input))
136
 
                                               ->nl_addr));
137
 
        if(lret != 0){
138
 
          fprintf_plus(stderr, "Failed to parse address %s: %s\n",
139
 
                       arg, nl_geterror(lret));
140
 
          argp_usage(state);
141
 
        }
142
 
        break;
143
 
      case 2:
144
 
        ((struct arguments *)(state->input))->interface = arg;
145
 
        break;
146
 
      default:
147
 
        argp_usage(state);
148
 
      }
149
 
      break;
150
 
    case ARGP_KEY_END:
151
 
      if(state->arg_num < 3){
152
 
        argp_usage(state);
153
 
      }
154
 
      break;
155
 
    default:
156
 
      return ARGP_ERR_UNKNOWN;
157
 
    }
158
 
    return errno;
159
 
  }
160
 
  
161
 
  struct argp argp = { .options = options, .parser = parse_opt,
162
 
                       .args_doc = "[ add | delete ] ADDRESS INTERFACE",
163
 
                       .doc = "Mandos client helper -- Add or delete"
164
 
                       " local route to IP address on interface" };
165
 
  
166
 
  ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &arguments);
167
 
  switch(ret){
168
 
  case 0:
169
 
    break;
170
 
  case EINVAL:
171
 
    exit(EX_USAGE);
172
 
  case ENOMEM:
173
 
  default:
174
 
    errno = ret;
175
 
    perror_plus("argp_parse");
176
 
    exitcode = EX_OSERR;
177
 
    goto end;
178
 
  }
179
 
  /* Get netlink socket */
180
 
  sk = nl_socket_alloc();
181
 
  if(sk == NULL){
182
 
    fprintf_plus(stderr, "Failed to allocate netlink socket: %s\n",
183
 
                 nl_geterror(ret));
184
 
    exitcode = EX_OSERR;
185
 
    goto end;
186
 
  }
187
 
  /* Connect socket to netlink */
188
 
  ret = nl_connect(sk, NETLINK_ROUTE);
189
 
  if(ret < 0){
190
 
    fprintf_plus(stderr, "Failed to connect socket to netlink: %s\n",
191
 
                 nl_geterror(ret));
192
 
    exitcode = EX_OSERR;
193
 
    goto end;
194
 
  }
195
 
  /* Get link object of specified interface */
196
 
  struct rtnl_link *link = NULL;
197
 
  ret = rtnl_link_get_kernel(sk, 0, arguments.interface, &link);
198
 
  if(ret < 0){
199
 
    fprintf_plus(stderr, "Failed to use interface %s: %s\n",
200
 
                 arguments.interface, nl_geterror(ret));
201
 
    exitcode = EX_OSERR;
202
 
    goto end;
203
 
  }
204
 
  /* Get netlink route object */
205
 
  route = rtnl_route_alloc();
206
 
  if(route == NULL){
207
 
    fprintf_plus(stderr, "Failed to get netlink route:\n");
208
 
    exitcode = EX_OSERR;
209
 
    goto end;
210
 
  }
211
 
  /* Get address family of specified address */
212
 
  sa_family_t af = (sa_family_t)nl_addr_get_family(arguments.nl_addr);
213
 
  if(debug){
214
 
    fprintf_plus(stderr, "Address family of %s is %s (%" PRIdMAX
215
 
                 ")\n", arguments.address,
216
 
                 af == AF_INET6 ? "AF_INET6" :
217
 
                 ( af == AF_INET ? "AF_INET" : "UNKNOWN"),
218
 
                 (intmax_t)af);
219
 
  }
220
 
  /* Set route parameters: */
221
 
  rtnl_route_set_family(route, (uint8_t)af);   /* Address family */
222
 
  rtnl_route_set_protocol(route, RTPROT_BOOT); /* protocol - see
223
 
                                                  ip-route(8) */
224
 
  rtnl_route_set_scope(route, RT_SCOPE_LINK); /* link scope */
225
 
  rtnl_route_set_type(route, RTN_UNICAST);    /* normal unicast
226
 
                                                 address route */
227
 
  rtnl_route_set_dst(route, arguments.nl_addr); /* Destination
228
 
                                                   address */
229
 
  rtnl_route_set_table(route, RT_TABLE_MAIN); /* "main" routing
230
 
                                                 table */
231
 
  /* Create nexthop */
232
 
  nexthop = rtnl_route_nh_alloc();
233
 
  if(nexthop == NULL){
234
 
    fprintf_plus(stderr, "Failed to get netlink route nexthop\n");
235
 
    exitcode = EX_OSERR;
236
 
    goto end;
237
 
  }
238
 
  /* Get index number of specified interface */
239
 
  int ifindex = rtnl_link_get_ifindex(link);
240
 
  if(debug){
241
 
    fprintf_plus(stderr, "ifindex of %s is %d\n", arguments.interface,
242
 
                 ifindex);
243
 
  }
244
 
  /* Set interface index number on nexthop object */
245
 
  rtnl_route_nh_set_ifindex(nexthop, ifindex);
246
 
  /* Set route tu use nexthop object */
247
 
  rtnl_route_add_nexthop(route, nexthop);
248
 
  /* Add or delete route? */
249
 
  if(arguments.add){
250
 
    ret = rtnl_route_add(sk, route, NLM_F_EXCL);
251
 
  } else {
252
 
    ret = rtnl_route_delete(sk, route, 0);
253
 
  }
254
 
  if(ret < 0){
255
 
     fprintf_plus(stderr, "Failed to %s route: %s\n",
256
 
                  arguments.add ? "add" : "delete",
257
 
                  nl_geterror(ret));
258
 
    exitcode = EX_OSERR;
259
 
    goto end;
260
 
  }
261
 
 end:
262
 
  /* Deallocate route */
263
 
  if(route){
264
 
    rtnl_route_put(route);
265
 
  } else if(nexthop) {
266
 
    /* Deallocate route nexthop */
267
 
    rtnl_route_nh_free(nexthop);
268
 
  }
269
 
  /* Deallocate parsed address */
270
 
  if(arguments.nl_addr){
271
 
    nl_addr_put(arguments.nl_addr);
272
 
  }
273
 
  /* Deallocate link struct */
274
 
  if(link){
275
 
    rtnl_link_put(link);
276
 
  }
277
 
  /* Deallocate netlink socket struct */
278
 
   if(sk){
279
 
    nl_socket_free(sk);
280
 
  }
281
 
  return exitcode;
282
 
}