/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: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

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 Teddy Hogeborn
6
 
 * Copyright © 2015 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 <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 */
39
 
 
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 */
48
 
 
49
 
bool debug = false;
50
 
const char *argp_program_version = "mandos-client-iprouteadddel " VERSION;
51
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
52
 
 
53
 
/* Function to use when printing errors */
54
 
void perror_plus(const char *print_text){
55
 
  int e = errno;
56
 
  fprintf(stderr, "Mandos plugin helper %s: ",
57
 
          program_invocation_short_name);
58
 
  errno = e;
59
 
  perror(print_text);
60
 
}
61
 
 
62
 
__attribute__((format (gnu_printf, 2, 3), nonnull))
63
 
int fprintf_plus(FILE *stream, const char *format, ...){
64
 
  va_list ap;
65
 
  va_start (ap, format);
66
 
  
67
 
  fprintf(stream, "Mandos plugin helper %s: ",
68
 
          program_invocation_short_name);
69
 
  return vfprintf(stream, format, ap);
70
 
}
71
 
 
72
 
int main(int argc, char *argv[]){
73
 
  int ret;
74
 
  int exitcode = EXIT_SUCCESS;
75
 
  struct arguments {
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" },
84
 
    { .name = NULL }
85
 
  };
86
 
  struct rtnl_route *route = NULL;
87
 
  struct rtnl_nexthop *nexthop = NULL;
88
 
  struct nl_sock *sk = NULL;
89
 
  
90
 
  error_t parse_opt(int key, char *arg, struct argp_state *state){
91
 
    int lret;
92
 
    errno = 0;
93
 
    switch(key){
94
 
    case 128:                   /* --debug */
95
 
      debug = true;
96
 
      break;
97
 
    case ARGP_KEY_ARG:
98
 
      switch(state->arg_num){
99
 
      case 0:
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;
104
 
        } else {
105
 
          fprintf_plus(stderr, "Unrecognized command: %s\n", arg);
106
 
          argp_usage(state);
107
 
        }
108
 
        break;
109
 
      case 1:
110
 
        ((struct arguments *)(state->input))->address = arg;
111
 
        lret = nl_addr_parse(arg, AF_UNSPEC, &(((struct arguments *)
112
 
                                                (state->input))
113
 
                                               ->nl_addr));
114
 
        if(lret != 0){
115
 
          fprintf_plus(stderr, "Failed to parse address %s: %s\n",
116
 
                       arg, nl_geterror(lret));
117
 
          argp_usage(state);
118
 
        }
119
 
        break;
120
 
      case 2:
121
 
        ((struct arguments *)(state->input))->interface = arg;
122
 
        break;
123
 
      default:
124
 
        argp_usage(state);
125
 
      }
126
 
      break;
127
 
    case ARGP_KEY_END:
128
 
      if(state->arg_num < 3){
129
 
        argp_usage(state);
130
 
      }
131
 
      break;
132
 
    default:
133
 
      return ARGP_ERR_UNKNOWN;
134
 
    }
135
 
    return errno;
136
 
  }
137
 
  
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" };
142
 
  
143
 
  ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &arguments);
144
 
  switch(ret){
145
 
  case 0:
146
 
    break;
147
 
  case EINVAL:
148
 
    exit(EX_USAGE);
149
 
  case ENOMEM:
150
 
  default:
151
 
    errno = ret;
152
 
    perror_plus("argp_parse");
153
 
    exitcode = EX_OSERR;
154
 
    goto end;
155
 
  }
156
 
  /* Get netlink socket */
157
 
  sk = nl_socket_alloc();
158
 
  if(sk == NULL){
159
 
    fprintf_plus(stderr, "Failed to allocate netlink socket: %s\n",
160
 
                 nl_geterror(ret));
161
 
    exitcode = EX_OSERR;
162
 
    goto end;
163
 
  }
164
 
  /* Connect socket to netlink */
165
 
  ret = nl_connect(sk, NETLINK_ROUTE);
166
 
  if(ret < 0){
167
 
    fprintf_plus(stderr, "Failed to connect socket to netlink: %s\n",
168
 
                 nl_geterror(ret));
169
 
    exitcode = EX_OSERR;
170
 
    goto end;
171
 
  }
172
 
  /* Get link object of specified interface */
173
 
  struct rtnl_link *link = NULL;
174
 
  ret = rtnl_link_get_kernel(sk, 0, arguments.interface, &link);
175
 
  if(ret < 0){
176
 
    fprintf_plus(stderr, "Failed to use interface %s: %s\n",
177
 
                 arguments.interface, nl_geterror(ret));
178
 
    exitcode = EX_OSERR;
179
 
    goto end;
180
 
  }
181
 
  /* Get netlink route object */
182
 
  route = rtnl_route_alloc();
183
 
  if(route == NULL){
184
 
    fprintf_plus(stderr, "Failed to get netlink route:\n");
185
 
    exitcode = EX_OSERR;
186
 
    goto end;
187
 
  }
188
 
  /* Get address family of specified address */
189
 
  sa_family_t af = (sa_family_t)nl_addr_get_family(arguments.nl_addr);
190
 
  if(debug){
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"),
195
 
                 (intmax_t)af);
196
 
  }
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
200
 
                                                  ip-route(8) */
201
 
  rtnl_route_set_scope(route, RT_SCOPE_LINK); /* link scope */
202
 
  rtnl_route_set_type(route, RTN_UNICAST);    /* normal unicast
203
 
                                                 address route */
204
 
  rtnl_route_set_dst(route, arguments.nl_addr); /* Destination
205
 
                                                   address */
206
 
  rtnl_route_set_table(route, RT_TABLE_MAIN); /* "main" routing
207
 
                                                 table */
208
 
  /* Create nexthop */
209
 
  nexthop = rtnl_route_nh_alloc();
210
 
  if(nexthop == NULL){
211
 
    fprintf_plus(stderr, "Failed to get netlink route nexthop:\n");
212
 
    exitcode = EX_OSERR;
213
 
    goto end;
214
 
  }
215
 
  /* Get index number of specified interface */
216
 
  int ifindex = rtnl_link_get_ifindex(link);
217
 
  if(debug){
218
 
    fprintf_plus(stderr, "ifindex of %s is %d\n", arguments.interface,
219
 
                 ifindex);
220
 
  }
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? */
226
 
  if(arguments.add){
227
 
    ret = rtnl_route_add(sk, route, NLM_F_EXCL);
228
 
  } else {
229
 
    ret = rtnl_route_delete(sk, route, 0);
230
 
  }
231
 
  if(ret < 0){
232
 
     fprintf_plus(stderr, "Failed to %s route: %s\n",
233
 
                  arguments.add ? "add" : "delete",
234
 
                  nl_geterror(ret));
235
 
    exitcode = EX_OSERR;
236
 
    goto end;
237
 
  }
238
 
 end:
239
 
  /* Deallocate route */
240
 
  if(route){
241
 
    rtnl_route_put(route);
242
 
  } else if(nexthop) {
243
 
    /* Deallocate route nexthop */
244
 
    rtnl_route_nh_free(nexthop);
245
 
  }
246
 
  /* Deallocate parsed address */
247
 
  if(arguments.nl_addr){
248
 
    nl_addr_put(arguments.nl_addr);
249
 
  }
250
 
  /* Deallocate link struct */
251
 
  if(link){
252
 
    rtnl_link_put(link);
253
 
  }
254
 
  /* Deallocate netlink socket struct */
255
 
   if(sk){
256
 
    nl_socket_free(sk);
257
 
  }
258
 
  return exitcode;
259
 
}