#include #include #include #include #include #include #include #include #include #include #include #include #include "dir.h" #include "vlink.h" #include "ht.h" #include "acl.h" #include "sig.h" #include "server.h" static SRVConfig srv_config; static const char *srv_llevel_str[] = { "DEBUG", "INFO", "ERROR" }; SRVConfig *srv_get_config(void) { return &srv_config; } static void usage(char *arg) { fprintf(stderr, "Usage: %s [ ] [ ]\n", arg); exit(1); } static void fail(char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); exit(1); } static void handle_err(ECPConnection *conn, unsigned char mtype, int err) { LOG(LOG_ERR, "handle_err: ctype:%d mtype:%d err:%d\n", conn->type, mtype, err); } static ECPConnection *conn_new(ECPSocket *sock, ECPConnection *parent, unsigned char ctype) { ECPConnection *conn = NULL; switch (ctype) { case CTYPE_DIR: { if (!(srv_config.capabilities & ECP_DIR_CAP_DIR)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) { ecp_conn_init(conn, sock, ctype); ecp_conn_set_flags(conn, ECP_CONN_FLAG_VBOX); } break; } case ECP_CTYPE_DIR: { if (!(srv_config.capabilities & ECP_DIR_CAP_DIR)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) ecp_conn_init(conn, sock, ctype); break; } case ECP_CTYPE_VCONN: { ECPVConnInb *_conn; if (!(srv_config.capabilities & ECP_DIR_CAP_VCONN)) return NULL; _conn = malloc(sizeof(ECPVConnInb)); if (_conn) { ecp_vconn_init_inb(_conn, sock); conn = &_conn->b; } break; } case ECP_CTYPE_VLINK: { if (!(srv_config.capabilities & ECP_DIR_CAP_VCONN)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) ecp_vlink_init(conn, sock); break; } } if (conn) ecp_conn_set_flags(conn, ECP_CONN_FLAG_GC); return conn; } static void conn_free(ECPConnection *conn) { free(conn); } static int key_check(ECPSocket *sock, ECPConnection *parent, unsigned char ctype, ecp_ecdh_public_t *public) { switch (ctype) { case CTYPE_DIR: { if (public == NULL) return 0; return acl_inlist(public); } case ECP_CTYPE_VLINK: { if (public == NULL) return 0; if (parent == NULL) return acl_inlist(public); return 1; } default: return 1; } } void log_print(int level, char *format, ...) { va_list args; time_t t; char buf[26]; if (level >= (sizeof(srv_llevel_str) / sizeof(char *))) return; t = time(NULL); ctime_r(&t, buf); buf[24] = '\0'; fprintf(stderr, "%s [%s]: ", buf, srv_llevel_str[level]); va_start(args, format); vfprintf(stderr, format, args); va_end(args); } int ecp_init(ECPContext *ctx, ECPConnHandler *vconn_handler, ECPConnHandler *vlink_handler) { int rv; rv = ecp_ctx_init(ctx, handle_err, conn_new, conn_free, key_check); if (rv) return rv; rv = ecp_vconn_handler_init(ctx, vconn_handler); if (rv) return rv; rv = ecp_vlink_handler_init(ctx, vlink_handler); if (rv) return rv; return ECP_OK; } int main(int argc, char *argv[]) { ecp_tr_addr_t addr; ECPContext ctx; ECPSocket sock; ECPConnHandler vconn_handler; ECPConnHandler vlink_handler; char *endptr; char *debug_init_str; int _argc, fd; int rv; memset(&srv_config, 0, sizeof(srv_config)); if (argc < 3) usage(argv[0]); _argc = 1; srv_config.region = (uint8_t)strtol(argv[_argc], &endptr, 16); if (endptr[0] != '\0') fail("Bad region\n"); if (srv_config.region >= MAX_REGION) fail("Bad region\n"); _argc++; srv_config.capabilities = (uint8_t)strtol(argv[_argc], &endptr, 16); if (endptr[0] != '\0') fail("Bad capabilities\n"); _argc++; if (srv_config.capabilities & ECP_DIR_CAP_DIR) { if (argc < 7) usage(argv[0]); } else { if (argc < 5) usage(argv[0]); } fd = open(argv[_argc], O_RDONLY); if (fd < 0) fail("Unable to open %s\n", argv[_argc]); rv = ecp_util_read_key(fd, &srv_config.key_perma.public, &srv_config.key_perma.private); close(fd); if (rv) fail("Unable to read key from %s\n", argv[_argc]); srv_config.key_perma.valid = 1; _argc++; rv = ecp_init(&ctx, &vconn_handler, &vlink_handler); if (rv) fail("ecp_init err:%d\n", rv); rv = ecp_sock_create(&sock, &ctx, &srv_config.key_perma); if (rv) fail("ecp_sock_create err:%d\n", rv); rv = ecp_vconn_sock_create(&sock); if (rv) fail("ecp_vconn_sock_create err:%d\n", rv); rv = ecp_addr_init(&addr, argv[_argc]); if (rv) fail("ecp_addr_init err:%d\n", rv); _argc++; rv = ecp_sock_open(&sock, &addr); if (rv) fail("ecp_sock_open err:%d\n", rv); srv_config.my_addr = addr; rv = acl_init(); if (rv) fail("acl_init err:%d\n", rv); if (srv_config.capabilities & ECP_DIR_CAP_DIR) { srv_config.acl_fn_dir = strdup(argv[_argc]); _argc++; srv_config.acl_fn = strdup(argv[_argc]); _argc++; rv = acl_load(); if (rv) fail("acl_load err:%d\n", rv); } rv = sig_init(); if (rv) fail("sig_init err:%d\n", rv); rv = dir_init(&sock); if (rv) fail("dir_init err:%d\n", rv); rv = vlink_init(&sock); if (rv) fail("vlink_init err:%d\n", rv); rv = ecp_start_receiver(&sock); if (rv) fail("ecp_start_receiver err:%d\n", rv); rv = sig_start_handler(&sock); if (rv) fail("sig_start_handler err:%d\n", rv); if (argc == _argc + 2) { ECPNode node; ecp_ecdh_public_t node_pub; ecp_tr_addr_t node_addr; fd = open(argv[_argc], O_RDONLY); if (fd < 0) fail("Unable to open %s\n", argv[_argc]); rv = ecp_util_read_key(fd, &node_pub, NULL); close(fd); if (rv) fail("Unable to read public key from %s\n", argv[_argc]); _argc++; ecp_node_init(&node, &node_pub, NULL); rv = ecp_node_set_addr(&node, argv[_argc]); if (rv) fail("ecp_node_set_addr err:%d\n", rv); _argc++; rv = dir_init_ann(&sock, &node); if (rv) fail("dir_init_ann err:%d\n", rv); } if (_argc != argc) usage(argv[0]); debug_init_str = getenv("ECP_DBG_INIT"); if (debug_init_str) { int init_ann; init_ann = (int)strtol(debug_init_str, &endptr, 10); if (endptr[0] == '\0') { LOG(LOG_DEBUG, "init switch start - number of announces:%d\n", init_ann); dir_init_switch(&sock, init_ann); LOG(LOG_DEBUG, "init switch done\n"); } } rv = dir_start_announce(&sock); if (rv) fail("dir_start_announce err:%d\n", rv); rv = vlink_start_keyx(&sock); if (rv) fail("vlink_start_keyx err:%d\n", rv); while(1) pause(); }