| 1 | /* Core interface of secnet, to be used by all modules */ |
| 2 | |
| 3 | #ifndef secnet_h |
| 4 | #define secnet_h |
| 5 | |
| 6 | #include "config.h" |
| 7 | #include <stdlib.h> |
| 8 | #include <stdarg.h> |
| 9 | #include <stdio.h> |
| 10 | #include <sys/poll.h> |
| 11 | #include <sys/types.h> |
| 12 | #include <sys/time.h> |
| 13 | #include <netinet/in.h> |
| 14 | |
| 15 | /* |
| 16 | * Macros added by SGT for endianness-independence |
| 17 | */ |
| 18 | #define GET_32BIT_MSB_FIRST(cp) \ |
| 19 | (((unsigned long)(unsigned char)(cp)[0] << 24) | \ |
| 20 | ((unsigned long)(unsigned char)(cp)[1] << 16) | \ |
| 21 | ((unsigned long)(unsigned char)(cp)[2] << 8) | \ |
| 22 | ((unsigned long)(unsigned char)(cp)[3])) |
| 23 | |
| 24 | #define PUT_32BIT_MSB_FIRST(cp, value) ( \ |
| 25 | (cp)[0] = (char)((value) >> 24), \ |
| 26 | (cp)[1] = (char)((value) >> 16), \ |
| 27 | (cp)[2] = (char)((value) >> 8), \ |
| 28 | (cp)[3] = (char)(value) ) |
| 29 | |
| 30 | typedef char *string_t; |
| 31 | typedef const char *cstring_t; |
| 32 | typedef enum {False,True} bool_t; |
| 33 | |
| 34 | #define ASSERT(x) do { if (!(x)) { fatal("assertion failed line %d file " \ |
| 35 | __FILE__,__LINE__); } } while(0) |
| 36 | |
| 37 | /* from logmsg.c */ |
| 38 | extern uint32_t message_level; |
| 39 | extern bool_t secnet_is_daemon; |
| 40 | extern struct log_if *system_log; |
| 41 | |
| 42 | /* from process.c */ |
| 43 | extern void start_signal_handling(void); |
| 44 | |
| 45 | /***** CONFIGURATION support *****/ |
| 46 | |
| 47 | extern bool_t just_check_config; /* If True then we're going to exit after |
| 48 | reading the configuration file */ |
| 49 | extern bool_t background; /* If True then we'll eventually run as a daemon */ |
| 50 | |
| 51 | typedef struct dict dict_t; /* Configuration dictionary */ |
| 52 | typedef struct closure closure_t; |
| 53 | typedef struct item item_t; |
| 54 | typedef struct list list_t; /* A list of items */ |
| 55 | |
| 56 | /* Configuration file location, for error-reporting */ |
| 57 | struct cloc { |
| 58 | cstring_t file; |
| 59 | uint32_t line; |
| 60 | }; |
| 61 | |
| 62 | /* Modules export closures, which can be invoked from the configuration file. |
| 63 | "Invoking" a closure usually returns another closure (of a different |
| 64 | type), but can actually return any configuration object. */ |
| 65 | typedef list_t *(apply_fn)(closure_t *self, struct cloc loc, |
| 66 | dict_t *context, list_t *data); |
| 67 | struct closure { |
| 68 | cstring_t description; /* For debugging */ |
| 69 | uint32_t type; /* Central registry... */ |
| 70 | apply_fn *apply; |
| 71 | void *interface; /* Interface for use inside secnet; depends on type */ |
| 72 | }; |
| 73 | |
| 74 | enum types { t_null, t_bool, t_string, t_number, t_dict, t_closure }; |
| 75 | struct item { |
| 76 | enum types type; |
| 77 | union { |
| 78 | bool_t bool; |
| 79 | string_t string; |
| 80 | uint32_t number; |
| 81 | dict_t *dict; |
| 82 | closure_t *closure; |
| 83 | } data; |
| 84 | struct cloc loc; |
| 85 | }; |
| 86 | |
| 87 | /* Note that it is unwise to use this structure directly; use the list |
| 88 | manipulation functions instead. */ |
| 89 | struct list { |
| 90 | item_t *item; |
| 91 | struct list *next; |
| 92 | }; |
| 93 | |
| 94 | /* In the following two lookup functions, NULL means 'not found' */ |
| 95 | /* Lookup a value in the specified dictionary, or its parents */ |
| 96 | extern list_t *dict_lookup(dict_t *dict, cstring_t key); |
| 97 | /* Lookup a value in just the specified dictionary */ |
| 98 | extern list_t *dict_lookup_primitive(dict_t *dict, cstring_t key); |
| 99 | /* Add a value to the specified dictionary */ |
| 100 | extern void dict_add(dict_t *dict, cstring_t key, list_t *val); |
| 101 | /* Obtain an array of keys in the dictionary. malloced; caller frees */ |
| 102 | extern cstring_t *dict_keys(dict_t *dict); |
| 103 | |
| 104 | /* List-manipulation functions */ |
| 105 | extern list_t *list_new(void); |
| 106 | extern uint32_t list_length(list_t *a); |
| 107 | extern list_t *list_append(list_t *a, item_t *i); |
| 108 | extern list_t *list_append_list(list_t *a, list_t *b); |
| 109 | /* Returns an item from the list (index starts at 0), or NULL */ |
| 110 | extern item_t *list_elem(list_t *l, uint32_t index); |
| 111 | |
| 112 | /* Convenience functions */ |
| 113 | extern list_t *new_closure(closure_t *cl); |
| 114 | extern void add_closure(dict_t *dict, cstring_t name, apply_fn apply); |
| 115 | extern void *find_cl_if(dict_t *dict, cstring_t name, uint32_t type, |
| 116 | bool_t fail_if_invalid, cstring_t desc, |
| 117 | struct cloc loc); |
| 118 | extern item_t *dict_find_item(dict_t *dict, cstring_t key, bool_t required, |
| 119 | cstring_t desc, struct cloc loc); |
| 120 | extern string_t dict_read_string(dict_t *dict, cstring_t key, bool_t required, |
| 121 | cstring_t desc, struct cloc loc); |
| 122 | extern uint32_t dict_read_number(dict_t *dict, cstring_t key, bool_t required, |
| 123 | cstring_t desc, struct cloc loc, |
| 124 | uint32_t def); |
| 125 | extern bool_t dict_read_bool(dict_t *dict, cstring_t key, bool_t required, |
| 126 | cstring_t desc, struct cloc loc, bool_t def); |
| 127 | struct flagstr { |
| 128 | cstring_t name; |
| 129 | uint32_t value; |
| 130 | }; |
| 131 | extern uint32_t string_to_word(cstring_t s, struct cloc loc, |
| 132 | struct flagstr *f, cstring_t desc); |
| 133 | extern uint32_t string_list_to_word(list_t *l, struct flagstr *f, |
| 134 | cstring_t desc); |
| 135 | |
| 136 | /***** END of configuration support *****/ |
| 137 | |
| 138 | /***** UTILITY functions *****/ |
| 139 | |
| 140 | extern char *safe_strdup(const char *string, const char *message); |
| 141 | extern void *safe_malloc(size_t size, const char *message); |
| 142 | |
| 143 | extern int sys_cmd(const char *file, const char *argc, ...); |
| 144 | |
| 145 | /***** END of utility functions *****/ |
| 146 | |
| 147 | /***** SCHEDULING support */ |
| 148 | |
| 149 | /* "now" is current program time, in milliseconds. It is derived |
| 150 | (once) from tv_now. If nfds_io is insufficient for your needs, set |
| 151 | it to the required number and return ERANGE. timeout is in milliseconds; |
| 152 | if it is too high then lower it. It starts at -1 (==infinite) */ |
| 153 | typedef int beforepoll_fn(void *st, struct pollfd *fds, int *nfds_io, |
| 154 | int *timeout_io, const struct timeval *tv_now, |
| 155 | uint64_t *now); |
| 156 | typedef void afterpoll_fn(void *st, struct pollfd *fds, int nfds, |
| 157 | const struct timeval *tv_now, uint64_t *now); |
| 158 | |
| 159 | /* Register interest in the main loop of the program. Before a call |
| 160 | to poll() your supplied beforepoll function will be called. After |
| 161 | the call to poll() the supplied afterpoll function will be called. |
| 162 | max_nfds is a _hint_ about the maximum number of struct pollfd |
| 163 | structures you may require - you can always ask for more in |
| 164 | *nfds_io. */ |
| 165 | extern void register_for_poll(void *st, beforepoll_fn *before, |
| 166 | afterpoll_fn *after, uint32_t max_nfds, |
| 167 | cstring_t desc); |
| 168 | |
| 169 | /***** END of scheduling support */ |
| 170 | |
| 171 | /***** PROGRAM LIFETIME support */ |
| 172 | |
| 173 | /* The secnet program goes through a number of phases in its lifetime. |
| 174 | Module code may arrange to be called just as various phases are |
| 175 | entered. */ |
| 176 | |
| 177 | #define PHASE_INIT 0 |
| 178 | #define PHASE_GETOPTS 1 /* Process command-line arguments */ |
| 179 | #define PHASE_READCONFIG 2 /* Parse and process configuration file */ |
| 180 | #define PHASE_SETUP 3 /* Process information in configuration */ |
| 181 | #define PHASE_GETRESOURCES 4 /* Obtain all external resources */ |
| 182 | #define PHASE_DROPPRIV 5 /* Last chance for privileged operations */ |
| 183 | #define PHASE_RUN 6 |
| 184 | #define PHASE_SHUTDOWN 7 /* About to die; delete key material, etc. */ |
| 185 | #define NR_PHASES 8 |
| 186 | |
| 187 | typedef void hook_fn(void *self, uint32_t newphase); |
| 188 | bool_t add_hook(uint32_t phase, hook_fn *f, void *state); |
| 189 | bool_t remove_hook(uint32_t phase, hook_fn *f, void *state); |
| 190 | |
| 191 | extern uint32_t current_phase; |
| 192 | extern void enter_phase(uint32_t new_phase); |
| 193 | |
| 194 | /* Some features (like netlink 'soft' routes) require that secnet |
| 195 | retain root privileges. They should indicate that here when |
| 196 | appropriate. */ |
| 197 | extern bool_t require_root_privileges; |
| 198 | extern cstring_t require_root_privileges_explanation; |
| 199 | |
| 200 | /***** END of program lifetime support *****/ |
| 201 | |
| 202 | /***** MODULE support *****/ |
| 203 | |
| 204 | /* Module initialisation function type - modules export one function of |
| 205 | this type which is called to initialise them. For dynamically loaded |
| 206 | modules it's called "secnet_module". */ |
| 207 | typedef void init_module(dict_t *dict); |
| 208 | |
| 209 | extern void init_builtin_modules(dict_t *dict); |
| 210 | |
| 211 | extern init_module resolver_module; |
| 212 | extern init_module random_module; |
| 213 | extern init_module udp_module; |
| 214 | extern init_module util_module; |
| 215 | extern init_module site_module; |
| 216 | extern init_module transform_module; |
| 217 | extern init_module netlink_module; |
| 218 | extern init_module rsa_module; |
| 219 | extern init_module dh_module; |
| 220 | extern init_module md5_module; |
| 221 | extern init_module slip_module; |
| 222 | extern init_module tun_module; |
| 223 | extern init_module sha1_module; |
| 224 | extern init_module log_module; |
| 225 | |
| 226 | /***** END of module support *****/ |
| 227 | |
| 228 | /***** CLOSURE TYPES and interface definitions *****/ |
| 229 | |
| 230 | #define CL_PURE 0 |
| 231 | #define CL_RESOLVER 1 |
| 232 | #define CL_RANDOMSRC 2 |
| 233 | #define CL_RSAPUBKEY 3 |
| 234 | #define CL_RSAPRIVKEY 4 |
| 235 | #define CL_COMM 5 |
| 236 | #define CL_IPIF 6 |
| 237 | #define CL_LOG 7 |
| 238 | #define CL_SITE 8 |
| 239 | #define CL_TRANSFORM 9 |
| 240 | #define CL_DH 11 |
| 241 | #define CL_HASH 12 |
| 242 | #define CL_BUFFER 13 |
| 243 | #define CL_NETLINK 14 |
| 244 | |
| 245 | struct buffer_if; |
| 246 | |
| 247 | /* PURE closure requires no interface */ |
| 248 | |
| 249 | /* RESOLVER interface */ |
| 250 | |
| 251 | /* Answers to queries are delivered to a function of this |
| 252 | type. 'address' will be NULL if there was a problem with the query. It |
| 253 | will be freed once resolve_answer_fn returns. It is in network byte |
| 254 | order. */ |
| 255 | /* XXX extend to be able to provide multiple answers */ |
| 256 | typedef void resolve_answer_fn(void *st, struct in_addr *addr); |
| 257 | typedef bool_t resolve_request_fn(void *st, cstring_t name, |
| 258 | resolve_answer_fn *cb, void *cst); |
| 259 | struct resolver_if { |
| 260 | void *st; |
| 261 | resolve_request_fn *request; |
| 262 | }; |
| 263 | |
| 264 | /* RANDOMSRC interface */ |
| 265 | |
| 266 | /* Return some random data. Returns TRUE for success. */ |
| 267 | typedef bool_t random_fn(void *st, uint32_t bytes, uint8_t *buff); |
| 268 | |
| 269 | struct random_if { |
| 270 | void *st; |
| 271 | bool_t blocking; |
| 272 | random_fn *generate; |
| 273 | }; |
| 274 | |
| 275 | /* RSAPUBKEY interface */ |
| 276 | |
| 277 | typedef bool_t rsa_checksig_fn(void *st, uint8_t *data, uint32_t datalen, |
| 278 | cstring_t signature); |
| 279 | struct rsapubkey_if { |
| 280 | void *st; |
| 281 | rsa_checksig_fn *check; |
| 282 | }; |
| 283 | |
| 284 | /* RSAPRIVKEY interface */ |
| 285 | |
| 286 | typedef string_t rsa_makesig_fn(void *st, uint8_t *data, uint32_t datalen); |
| 287 | struct rsaprivkey_if { |
| 288 | void *st; |
| 289 | rsa_makesig_fn *sign; |
| 290 | }; |
| 291 | |
| 292 | /* COMM interface */ |
| 293 | |
| 294 | /* Return True if the packet was processed, and shouldn't be passed to |
| 295 | any other potential receivers. */ |
| 296 | typedef bool_t comm_notify_fn(void *state, struct buffer_if *buf, |
| 297 | struct sockaddr_in *source); |
| 298 | typedef void comm_request_notify_fn(void *commst, void *nst, |
| 299 | comm_notify_fn *fn); |
| 300 | typedef void comm_release_notify_fn(void *commst, void *nst, |
| 301 | comm_notify_fn *fn); |
| 302 | typedef bool_t comm_sendmsg_fn(void *commst, struct buffer_if *buf, |
| 303 | struct sockaddr_in *dest); |
| 304 | struct comm_if { |
| 305 | void *st; |
| 306 | uint32_t min_start_pad; |
| 307 | uint32_t min_end_pad; |
| 308 | comm_request_notify_fn *request_notify; |
| 309 | comm_release_notify_fn *release_notify; |
| 310 | comm_sendmsg_fn *sendmsg; |
| 311 | }; |
| 312 | |
| 313 | /* LOG interface */ |
| 314 | |
| 315 | typedef void log_msg_fn(void *st, int class, const char *message, ...); |
| 316 | typedef void log_vmsg_fn(void *st, int class, const char *message, |
| 317 | va_list args); |
| 318 | struct log_if { |
| 319 | void *st; |
| 320 | log_msg_fn *log; |
| 321 | log_vmsg_fn *vlog; |
| 322 | }; |
| 323 | /* (convenience function, defined in util.c) */ |
| 324 | extern void slilog(struct log_if *lf, int class, const char *message, ...) |
| 325 | FORMAT(printf,3,4); |
| 326 | |
| 327 | /* SITE interface */ |
| 328 | |
| 329 | /* Pretty much a placeholder; allows starting and stopping of processing, |
| 330 | key expiry, etc. */ |
| 331 | typedef void site_control_fn(void *st, bool_t run); |
| 332 | typedef uint32_t site_status_fn(void *st); |
| 333 | struct site_if { |
| 334 | void *st; |
| 335 | site_control_fn *control; |
| 336 | site_status_fn *status; |
| 337 | }; |
| 338 | |
| 339 | /* TRANSFORM interface */ |
| 340 | |
| 341 | /* A reversable transformation. Transforms buffer in-place; may add |
| 342 | data to start or end. Maximum amount of data to be added specified |
| 343 | in max_start_pad and max_end_pad. (Reverse transformations decrease |
| 344 | length, of course.) Transformations may be key-dependent, in which |
| 345 | case key material is passed in at initialisation time. They may |
| 346 | also depend on internal factors (eg. time) and keep internal |
| 347 | state. A struct transform_if only represents a particular type of |
| 348 | transformation; instances of the transformation (eg. with |
| 349 | particular key material) have a different C type. */ |
| 350 | |
| 351 | typedef struct transform_inst_if *transform_createinstance_fn(void *st); |
| 352 | typedef bool_t transform_setkey_fn(void *st, uint8_t *key, uint32_t keylen); |
| 353 | typedef void transform_delkey_fn(void *st); |
| 354 | typedef void transform_destroyinstance_fn(void *st); |
| 355 | /* Returns 0 for 'all is well', any other value for a problem */ |
| 356 | typedef uint32_t transform_apply_fn(void *st, struct buffer_if *buf, |
| 357 | const char **errmsg); |
| 358 | |
| 359 | struct transform_inst_if { |
| 360 | void *st; |
| 361 | transform_setkey_fn *setkey; |
| 362 | transform_delkey_fn *delkey; |
| 363 | transform_apply_fn *forwards; |
| 364 | transform_apply_fn *reverse; |
| 365 | transform_destroyinstance_fn *destroy; |
| 366 | }; |
| 367 | |
| 368 | struct transform_if { |
| 369 | void *st; |
| 370 | uint32_t max_start_pad; |
| 371 | uint32_t max_end_pad; |
| 372 | uint32_t keylen; |
| 373 | transform_createinstance_fn *create; |
| 374 | }; |
| 375 | |
| 376 | /* NETLINK interface */ |
| 377 | |
| 378 | /* Used by netlink to deliver to site, and by site to deliver to |
| 379 | netlink. cid is the client identifier returned by |
| 380 | netlink_regnets_fn. If buf has size 0 then the function is just |
| 381 | being called for its site-effects (eg. making the site code attempt |
| 382 | to bring up a network link) */ |
| 383 | typedef void netlink_deliver_fn(void *st, struct buffer_if *buf); |
| 384 | /* site code can tell netlink when outgoing packets will be dropped, |
| 385 | so netlink can generate appropriate ICMP and make routing decisions */ |
| 386 | #define LINK_QUALITY_DOWN 0 /* No chance of a packet being delivered */ |
| 387 | #define LINK_QUALITY_DOWN_STALE_ADDRESS 1 /* Link down, old address information */ |
| 388 | #define LINK_QUALITY_DOWN_CURRENT_ADDRESS 2 /* Link down, current address information */ |
| 389 | #define LINK_QUALITY_UP 3 /* Link active */ |
| 390 | #define MAXIMUM_LINK_QUALITY 3 |
| 391 | typedef void netlink_link_quality_fn(void *st, uint32_t quality); |
| 392 | typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver, |
| 393 | void *dst, uint32_t max_start_pad, |
| 394 | uint32_t max_end_pad); |
| 395 | typedef void netlink_output_config_fn(void *st, struct buffer_if *buf); |
| 396 | typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf); |
| 397 | typedef void netlink_set_mtu_fn(void *st, uint32_t new_mtu); |
| 398 | struct netlink_if { |
| 399 | void *st; |
| 400 | netlink_register_fn *reg; |
| 401 | netlink_deliver_fn *deliver; |
| 402 | netlink_link_quality_fn *set_quality; |
| 403 | netlink_output_config_fn *output_config; |
| 404 | netlink_check_config_fn *check_config; |
| 405 | netlink_set_mtu_fn *set_mtu; |
| 406 | }; |
| 407 | |
| 408 | /* DH interface */ |
| 409 | |
| 410 | /* Returns public key as a malloced hex string */ |
| 411 | typedef string_t dh_makepublic_fn(void *st, uint8_t *secret, |
| 412 | uint32_t secretlen); |
| 413 | /* Fills buffer (up to buflen) with shared secret */ |
| 414 | typedef void dh_makeshared_fn(void *st, uint8_t *secret, |
| 415 | uint32_t secretlen, cstring_t rempublic, |
| 416 | uint8_t *sharedsecret, uint32_t buflen); |
| 417 | struct dh_if { |
| 418 | void *st; |
| 419 | uint32_t len; /* Approximate size of modulus in bytes */ |
| 420 | dh_makepublic_fn *makepublic; |
| 421 | dh_makeshared_fn *makeshared; |
| 422 | }; |
| 423 | |
| 424 | /* HASH interface */ |
| 425 | |
| 426 | typedef void *hash_init_fn(void); |
| 427 | typedef void hash_update_fn(void *st, uint8_t const *buf, uint32_t len); |
| 428 | typedef void hash_final_fn(void *st, uint8_t *digest); |
| 429 | struct hash_if { |
| 430 | uint32_t len; /* Hash output length in bytes */ |
| 431 | hash_init_fn *init; |
| 432 | hash_update_fn *update; |
| 433 | hash_final_fn *final; |
| 434 | }; |
| 435 | |
| 436 | /* BUFFER interface */ |
| 437 | |
| 438 | struct buffer_if { |
| 439 | bool_t free; |
| 440 | cstring_t owner; /* Set to constant string */ |
| 441 | uint32_t flags; /* How paranoid should we be? */ |
| 442 | struct cloc loc; /* Where we were defined */ |
| 443 | uint8_t *base; |
| 444 | uint8_t *start; |
| 445 | uint32_t size; /* Size of buffer contents */ |
| 446 | uint32_t len; /* Total length allocated at base */ |
| 447 | }; |
| 448 | |
| 449 | /***** LOG functions *****/ |
| 450 | |
| 451 | #define M_DEBUG_CONFIG 0x001 |
| 452 | #define M_DEBUG_PHASE 0x002 |
| 453 | #define M_DEBUG 0x004 |
| 454 | #define M_INFO 0x008 |
| 455 | #define M_NOTICE 0x010 |
| 456 | #define M_WARNING 0x020 |
| 457 | #define M_ERR 0x040 |
| 458 | #define M_SECURITY 0x080 |
| 459 | #define M_FATAL 0x100 |
| 460 | |
| 461 | /* The fatal() family of functions require messages that do not end in '\n' */ |
| 462 | extern NORETURN(fatal(const char *message, ...)); |
| 463 | extern NORETURN(fatal_perror(const char *message, ...)); |
| 464 | extern NORETURN(fatal_status(int status, const char *message, ...)); |
| 465 | extern NORETURN(fatal_perror_status(int status, const char *message, ...)); |
| 466 | |
| 467 | /* The cfgfatal() family of functions require messages that end in '\n' */ |
| 468 | extern NORETURN(cfgfatal(struct cloc loc, cstring_t facility, |
| 469 | const char *message, ...)); |
| 470 | extern void cfgfile_postreadcheck(struct cloc loc, FILE *f); |
| 471 | extern NORETURN(vcfgfatal_maybefile(FILE *maybe_f, struct cloc loc, |
| 472 | cstring_t facility, const char *message, |
| 473 | va_list)); |
| 474 | extern NORETURN(cfgfatal_maybefile(FILE *maybe_f, struct cloc loc, |
| 475 | cstring_t facility, |
| 476 | const char *message, ...)); |
| 477 | |
| 478 | extern void Message(uint32_t class, const char *message, ...) |
| 479 | FORMAT(printf,2,3); |
| 480 | extern void log_from_fd(int fd, cstring_t prefix, struct log_if *log); |
| 481 | |
| 482 | /***** END of log functions *****/ |
| 483 | |
| 484 | #endif /* secnet_h */ |