From: Guus Sliepen Date: Sat, 7 Oct 2017 15:49:45 +0000 (+0200) Subject: Reformat all code using astyle. X-Git-Tag: release-1.0.33~17 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=3fae14fae5a347823679ef694ab630b4991a201d;p=oweals%2Ftinc.git Reformat all code using astyle. --- diff --git a/src/avl_tree.c b/src/avl_tree.c index 0d122bf..96d3d43 100644 --- a/src/avl_tree.c +++ b/src/avl_tree.c @@ -50,14 +50,14 @@ #endif #ifndef AVL_DEPTH -static int lg(unsigned int u) __attribute__ ((__const__)); +static int lg(unsigned int u) __attribute__((__const__)); -static int lg(unsigned int u) -{ +static int lg(unsigned int u) { int r = 1; - if(!u) + if(!u) { return 0; + } if(u & 0xffff0000) { u >>= 16; @@ -79,8 +79,9 @@ static int lg(unsigned int u) r += 2; } - if(u & 0x00000002) + if(u & 0x00000002) { r++; + } return r; } @@ -88,8 +89,7 @@ static int lg(unsigned int u) /* Internal helper functions */ -static int avl_check_balance(const avl_node_t *node) -{ +static int avl_check_balance(const avl_node_t *node) { #ifdef AVL_DEPTH int d; @@ -97,27 +97,28 @@ static int avl_check_balance(const avl_node_t *node) return d < -1 ? -1 : d > 1 ? 1 : 0; #else -/* int d; - * d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node)); - * d = d<-1?-1:d>1?1:0; - */ + /* int d; + * d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node)); + * d = d<-1?-1:d>1?1:0; + */ int pl, r; pl = lg(AVL_L_COUNT(node)); r = AVL_R_COUNT(node); - if(r >> pl + 1) + if(r >> pl + 1) { return 1; + } - if(pl < 2 || r >> pl - 2) + if(pl < 2 || r >> pl - 2) { return 0; + } return -1; #endif } -static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) -{ +static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) { avl_node_t *child; avl_node_t *gchild; avl_node_t *parent; @@ -127,135 +128,154 @@ static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) parent = node->parent; superparent = - parent ? node == - parent->left ? &parent->left : &parent->right : &tree->root; + parent ? node == + parent->left ? &parent->left : &parent->right : &tree->root; - switch (avl_check_balance(node)) { - case -1: - child = node->left; + switch(avl_check_balance(node)) { + case -1: + child = node->left; #ifdef AVL_DEPTH - if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) { + + if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) { #else - if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) { + + if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) { #endif - node->left = child->right; - if(node->left) - node->left->parent = node; - - child->right = node; - node->parent = child; - *superparent = child; - child->parent = parent; + node->left = child->right; + + if(node->left) { + node->left->parent = node; + } + + child->right = node; + node->parent = child; + *superparent = child; + child->parent = parent; #ifdef AVL_COUNT - node->count = AVL_CALC_COUNT(node); - child->count = AVL_CALC_COUNT(child); + node->count = AVL_CALC_COUNT(node); + child->count = AVL_CALC_COUNT(child); #endif #ifdef AVL_DEPTH - node->depth = AVL_CALC_DEPTH(node); - child->depth = AVL_CALC_DEPTH(child); + node->depth = AVL_CALC_DEPTH(node); + child->depth = AVL_CALC_DEPTH(child); #endif - } else { - gchild = child->right; - node->left = gchild->right; + } else { + gchild = child->right; + node->left = gchild->right; - if(node->left) - node->left->parent = node; - child->right = gchild->left; + if(node->left) { + node->left->parent = node; + } + + child->right = gchild->left; + + if(child->right) { + child->right->parent = child; + } - if(child->right) - child->right->parent = child; - gchild->right = node; + gchild->right = node; - gchild->right->parent = gchild; - gchild->left = child; + gchild->right->parent = gchild; + gchild->left = child; - gchild->left->parent = gchild; + gchild->left->parent = gchild; - *superparent = gchild; - gchild->parent = parent; + *superparent = gchild; + gchild->parent = parent; #ifdef AVL_COUNT - node->count = AVL_CALC_COUNT(node); - child->count = AVL_CALC_COUNT(child); - gchild->count = AVL_CALC_COUNT(gchild); + node->count = AVL_CALC_COUNT(node); + child->count = AVL_CALC_COUNT(child); + gchild->count = AVL_CALC_COUNT(gchild); #endif #ifdef AVL_DEPTH - node->depth = AVL_CALC_DEPTH(node); - child->depth = AVL_CALC_DEPTH(child); - gchild->depth = AVL_CALC_DEPTH(gchild); + node->depth = AVL_CALC_DEPTH(node); + child->depth = AVL_CALC_DEPTH(child); + gchild->depth = AVL_CALC_DEPTH(gchild); #endif - } - break; + } + + break; - case 1: - child = node->right; + case 1: + child = node->right; #ifdef AVL_DEPTH - if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) { + + if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) { #else - if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) { + + if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) { #endif - node->right = child->left; - if(node->right) - node->right->parent = node; - child->left = node; - node->parent = child; - *superparent = child; - child->parent = parent; + node->right = child->left; + + if(node->right) { + node->right->parent = node; + } + + child->left = node; + node->parent = child; + *superparent = child; + child->parent = parent; #ifdef AVL_COUNT - node->count = AVL_CALC_COUNT(node); - child->count = AVL_CALC_COUNT(child); + node->count = AVL_CALC_COUNT(node); + child->count = AVL_CALC_COUNT(child); #endif #ifdef AVL_DEPTH - node->depth = AVL_CALC_DEPTH(node); - child->depth = AVL_CALC_DEPTH(child); + node->depth = AVL_CALC_DEPTH(node); + child->depth = AVL_CALC_DEPTH(child); #endif - } else { - gchild = child->left; - node->right = gchild->left; + } else { + gchild = child->left; + node->right = gchild->left; + + if(node->right) { + node->right->parent = node; + } - if(node->right) - node->right->parent = node; - child->left = gchild->right; + child->left = gchild->right; + + if(child->left) { + child->left->parent = child; + } - if(child->left) - child->left->parent = child; - gchild->left = node; + gchild->left = node; - gchild->left->parent = gchild; - gchild->right = child; + gchild->left->parent = gchild; + gchild->right = child; - gchild->right->parent = gchild; + gchild->right->parent = gchild; - *superparent = gchild; - gchild->parent = parent; + *superparent = gchild; + gchild->parent = parent; #ifdef AVL_COUNT - node->count = AVL_CALC_COUNT(node); - child->count = AVL_CALC_COUNT(child); - gchild->count = AVL_CALC_COUNT(gchild); + node->count = AVL_CALC_COUNT(node); + child->count = AVL_CALC_COUNT(child); + gchild->count = AVL_CALC_COUNT(gchild); #endif #ifdef AVL_DEPTH - node->depth = AVL_CALC_DEPTH(node); - child->depth = AVL_CALC_DEPTH(child); - gchild->depth = AVL_CALC_DEPTH(gchild); + node->depth = AVL_CALC_DEPTH(node); + child->depth = AVL_CALC_DEPTH(child); + gchild->depth = AVL_CALC_DEPTH(gchild); #endif - } - break; + } - default: + break; + + default: #ifdef AVL_COUNT - node->count = AVL_CALC_COUNT(node); + node->count = AVL_CALC_COUNT(node); #endif #ifdef AVL_DEPTH - node->depth = AVL_CALC_DEPTH(node); + node->depth = AVL_CALC_DEPTH(node); #endif } + node = parent; } } /* (De)constructors */ -avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) -{ +avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) { avl_tree_t *tree; tree = xmalloc_and_zero(sizeof(avl_tree_t)); @@ -265,28 +285,25 @@ avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) return tree; } -void avl_free_tree(avl_tree_t *tree) -{ +void avl_free_tree(avl_tree_t *tree) { free(tree); } -avl_node_t *avl_alloc_node(void) -{ +avl_node_t *avl_alloc_node(void) { return xmalloc_and_zero(sizeof(avl_node_t)); } -void avl_free_node(avl_tree_t *tree, avl_node_t *node) -{ - if(node->data && tree->delete) +void avl_free_node(avl_tree_t *tree, avl_node_t *node) { + if(node->data && tree->delete) { tree->delete(node->data); + } free(node); } /* Searching */ -void *avl_search(const avl_tree_t *tree, const void *data) -{ +void *avl_search(const avl_tree_t *tree, const void *data) { avl_node_t *node; node = avl_search_node(tree, data); @@ -294,8 +311,7 @@ void *avl_search(const avl_tree_t *tree, const void *data) return node ? node->data : NULL; } -void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) -{ +void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) { avl_node_t *node; node = avl_search_closest_node(tree, data, result); @@ -303,8 +319,7 @@ void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) return node ? node->data : NULL; } -void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) -{ +void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) { avl_node_t *node; node = avl_search_closest_smaller_node(tree, data); @@ -312,8 +327,7 @@ void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) return node ? node->data : NULL; } -void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) -{ +void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) { avl_node_t *node; node = avl_search_closest_greater_node(tree, data); @@ -321,8 +335,7 @@ void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) return node ? node->data : NULL; } -avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) -{ +avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) { avl_node_t *node; int result; @@ -332,16 +345,17 @@ avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) } avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, - int *result) -{ + int *result) { avl_node_t *node; int c; node = tree->root; if(!node) { - if(result) + if(result) { *result = 0; + } + return NULL; } @@ -349,24 +363,30 @@ avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, c = tree->compare(data, node->data); if(c < 0) { - if(node->left) + if(node->left) { node = node->left; - else { - if(result) + } else { + if(result) { *result = -1; + } + break; } } else if(c > 0) { - if(node->right) + if(node->right) { node = node->right; - else { - if(result) + } else { + if(result) { *result = 1; + } + break; } } else { - if(result) + if(result) { *result = 0; + } + break; } } @@ -375,37 +395,36 @@ avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, } avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, - const void *data) -{ + const void *data) { avl_node_t *node; int result; node = avl_search_closest_node(tree, data, &result); - if(result < 0) + if(result < 0) { node = node->prev; + } return node; } avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, - const void *data) -{ + const void *data) { avl_node_t *node; int result; node = avl_search_closest_node(tree, data, &result); - if(result > 0) + if(result > 0) { node = node->next; + } return node; } /* Insertion and deletion */ -avl_node_t *avl_insert(avl_tree_t *tree, void *data) -{ +avl_node_t *avl_insert(avl_tree_t *tree, void *data) { avl_node_t *closest, *new; int result; @@ -416,21 +435,21 @@ avl_node_t *avl_insert(avl_tree_t *tree, void *data) } else { closest = avl_search_closest_node(tree, data, &result); - switch (result) { - case -1: - new = avl_alloc_node(); - new->data = data; - avl_insert_before(tree, closest, new); - break; + switch(result) { + case -1: + new = avl_alloc_node(); + new->data = data; + avl_insert_before(tree, closest, new); + break; - case 1: - new = avl_alloc_node(); - new->data = data; - avl_insert_after(tree, closest, new); - break; + case 1: + new = avl_alloc_node(); + new->data = data; + avl_insert_after(tree, closest, new); + break; - default: - return NULL; + default: + return NULL; } } @@ -444,27 +463,26 @@ avl_node_t *avl_insert(avl_tree_t *tree, void *data) return new; } -avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) -{ +avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) { avl_node_t *closest; int result; - if(!tree->root) + if(!tree->root) { avl_insert_top(tree, node); - else { + } else { closest = avl_search_closest_node(tree, node->data, &result); - switch (result) { - case -1: - avl_insert_before(tree, closest, node); - break; + switch(result) { + case -1: + avl_insert_before(tree, closest, node); + break; - case 1: - avl_insert_after(tree, closest, node); - break; + case 1: + avl_insert_after(tree, closest, node); + break; - case 0: - return NULL; + case 0: + return NULL; } } @@ -478,20 +496,20 @@ avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) return node; } -void avl_insert_top(avl_tree_t *tree, avl_node_t *node) -{ +void avl_insert_top(avl_tree_t *tree, avl_node_t *node) { node->prev = node->next = node->parent = NULL; tree->head = tree->tail = tree->root = node; } void avl_insert_before(avl_tree_t *tree, avl_node_t *before, - avl_node_t *node) -{ + avl_node_t *node) { if(!before) { - if(tree->tail) + if(tree->tail) { avl_insert_after(tree, tree->tail, node); - else + } else { avl_insert_top(tree, node); + } + return; } @@ -504,10 +522,11 @@ void avl_insert_before(avl_tree_t *tree, avl_node_t *before, return; } - if(before->prev) + if(before->prev) { before->prev->next = node; - else + } else { tree->head = node; + } before->prev = node; before->left = node; @@ -515,13 +534,14 @@ void avl_insert_before(avl_tree_t *tree, avl_node_t *before, avl_rebalance(tree, before); } -void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) -{ +void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) { if(!after) { - if(tree->head) + if(tree->head) { avl_insert_before(tree, tree->head, node); - else + } else { avl_insert_top(tree, node); + } + return; } @@ -534,10 +554,11 @@ void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) node->parent = after; node->next = after->next; - if(after->next) + if(after->next) { after->next->prev = node; - else + } else { tree->tail = node; + } after->next = node; after->right = node; @@ -545,47 +566,51 @@ void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) avl_rebalance(tree, after); } -avl_node_t *avl_unlink(avl_tree_t *tree, void *data) -{ +avl_node_t *avl_unlink(avl_tree_t *tree, void *data) { avl_node_t *node; node = avl_search_node(tree, data); - if(node) + if(node) { avl_unlink_node(tree, node); + } return node; } -void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) -{ +void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) { avl_node_t *parent; avl_node_t **superparent; avl_node_t *subst, *left, *right; avl_node_t *balnode; - if(node->prev) + if(node->prev) { node->prev->next = node->next; - else + } else { tree->head = node->next; - if(node->next) + } + + if(node->next) { node->next->prev = node->prev; - else + } else { tree->tail = node->prev; + } parent = node->parent; superparent = - parent ? node == - parent->left ? &parent->left : &parent->right : &tree->root; + parent ? node == + parent->left ? &parent->left : &parent->right : &tree->root; left = node->left; right = node->right; + if(!left) { *superparent = right; - if(right) + if(right) { right->parent = parent; + } balnode = parent; } else if(!right) { @@ -594,8 +619,10 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) balnode = parent; } else { subst = node->prev; - if(!subst) // This only happens if node is not actually in a tree at all. + + if(!subst) { // This only happens if node is not actually in a tree at all. abort(); + } if(subst == left) { balnode = subst; @@ -603,8 +630,9 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) balnode = subst->parent; balnode->right = subst->left; - if(balnode->right) + if(balnode->right) { balnode->right->parent = balnode; + } subst->left = left; left->parent = subst; @@ -628,26 +656,24 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) #endif } -void avl_delete_node(avl_tree_t *tree, avl_node_t *node) -{ +void avl_delete_node(avl_tree_t *tree, avl_node_t *node) { avl_unlink_node(tree, node); avl_free_node(tree, node); } -void avl_delete(avl_tree_t *tree, void *data) -{ +void avl_delete(avl_tree_t *tree, void *data) { avl_node_t *node; node = avl_search_node(tree, data); - if(node) + if(node) { avl_delete_node(tree, node); + } } /* Fast tree cleanup */ -void avl_delete_tree(avl_tree_t *tree) -{ +void avl_delete_tree(avl_tree_t *tree) { avl_node_t *node, *next; for(node = tree->head; node; node = next) { @@ -660,8 +686,7 @@ void avl_delete_tree(avl_tree_t *tree) /* Tree walking */ -void avl_foreach(const avl_tree_t *tree, avl_action_t action) -{ +void avl_foreach(const avl_tree_t *tree, avl_action_t action) { avl_node_t *node, *next; for(node = tree->head; node; node = next) { @@ -670,8 +695,7 @@ void avl_foreach(const avl_tree_t *tree, avl_action_t action) } } -void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) -{ +void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) { avl_node_t *node, *next; for(node = tree->head; node; node = next) { @@ -683,13 +707,11 @@ void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) /* Indexing */ #ifdef AVL_COUNT -unsigned int avl_count(const avl_tree_t *tree) -{ +unsigned int avl_count(const avl_tree_t *tree) { return AVL_NODE_COUNT(tree->root); } -avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) -{ +avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) { avl_node_t *node; unsigned int c; @@ -711,16 +733,17 @@ avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) return NULL; } -unsigned int avl_index(const avl_node_t *node) -{ +unsigned int avl_index(const avl_node_t *node) { avl_node_t *next; unsigned int index; index = AVL_L_COUNT(node); while((next = node->parent)) { - if(node == next->right) + if(node == next->right) { index += AVL_L_COUNT(next) + 1; + } + node = next; } @@ -728,8 +751,7 @@ unsigned int avl_index(const avl_node_t *node) } #endif #ifdef AVL_DEPTH -unsigned int avl_depth(const avl_tree_t *tree) -{ +unsigned int avl_depth(const avl_tree_t *tree) { return AVL_NODE_DEPTH(tree->root); } #endif diff --git a/src/bsd/device.c b/src/bsd/device.c index f6614b2..62e7e84 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -69,12 +69,14 @@ static device_type_t device_type = DEVICE_TYPE_TUN; #ifdef HAVE_NET_IF_UTUN_H static bool setup_utun(void) { device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if(device_fd == -1) { logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno)); return false; } struct ctl_info info = {}; + strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name)); if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) { @@ -84,10 +86,13 @@ static bool setup_utun(void) { int unit = -1; char *p = strstr(device, "utun"), *e = NULL; + if(p) { unit = strtol(p + 4, &e, 10); - if(!e) + + if(!e) { unit = -1; + } } struct sockaddr_ctl sc = { @@ -105,6 +110,7 @@ static bool setup_utun(void) { char name[64] = ""; socklen_t len = sizeof(name); + if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) { iface = xstrdup(device); } else { @@ -123,10 +129,11 @@ static bool setup_device(void) { // Find out which device file to open if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { - if(routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { device = xstrdup(DEFAULT_TUN_DEVICE); - else + } else { device = xstrdup(DEFAULT_TAP_DEVICE); + } } // Find out if it's supposed to be a tun or a tap device @@ -135,33 +142,40 @@ static bool setup_device(void) { if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(!strcasecmp(type, "tun")) - /* use default */; + /* use default */; + #ifdef ENABLE_TUNEMU - else if(!strcasecmp(type, "tunemu")) + else if(!strcasecmp(type, "tunemu")) { device_type = DEVICE_TYPE_TUNEMU; + } + #endif #ifdef HAVE_NET_IF_UTUN_H - else if(!strcasecmp(type, "utun")) + else if(!strcasecmp(type, "utun")) { device_type = DEVICE_TYPE_UTUN; + } + #endif - else if(!strcasecmp(type, "tunnohead")) + else if(!strcasecmp(type, "tunnohead")) { device_type = DEVICE_TYPE_TUN; - else if(!strcasecmp(type, "tunifhead")) + } else if(!strcasecmp(type, "tunifhead")) { device_type = DEVICE_TYPE_TUNIFHEAD; - else if(!strcasecmp(type, "tap")) + } else if(!strcasecmp(type, "tap")) { device_type = DEVICE_TYPE_TAP; - else { + } else { logger(LOG_ERR, "Unknown device type %s!", type); return false; } } else { #ifdef HAVE_NET_IF_UTUN_H - if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) + + if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) { device_type = DEVICE_TYPE_UTUN; - else + } else #endif - if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) - device_type = DEVICE_TYPE_TAP; + if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) { + device_type = DEVICE_TYPE_TAP; + } } if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) { @@ -173,18 +187,21 @@ static bool setup_device(void) { switch(device_type) { #ifdef ENABLE_TUNEMU - case DEVICE_TYPE_TUNEMU: { - char dynamic_name[256] = ""; - device_fd = tunemu_open(dynamic_name); - } - break; + + case DEVICE_TYPE_TUNEMU: { + char dynamic_name[256] = ""; + device_fd = tunemu_open(dynamic_name); + } + break; #endif #ifdef HAVE_NET_IF_UTUN_H - case DEVICE_TYPE_UTUN: - return setup_utun(); + + case DEVICE_TYPE_UTUN: + return setup_utun(); #endif - default: - device_fd = open(device, O_RDWR | O_NONBLOCK); + + default: + device_fd = open(device, O_RDWR | O_NONBLOCK); } if(device_fd < 0) { @@ -204,32 +221,40 @@ static bool setup_device(void) { realname = fdevname(device_fd); #elif defined(HAVE_DEVNAME) struct stat buf; - if(!fstat(device_fd, &buf)) + + if(!fstat(device_fd, &buf)) { realname = devname(buf.st_rdev, S_IFCHR); + } + #endif - if(!realname) + if(!realname) { realname = device; + } - if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) + if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) { iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname); - else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) + } else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) { logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly."); + } // Configure the device as best as we can switch(device_type) { - default: - device_type = DEVICE_TYPE_TUN; - case DEVICE_TYPE_TUN: + default: + device_type = DEVICE_TYPE_TUN; + + case DEVICE_TYPE_TUN: #ifdef TUNSIFHEAD - { + { const int zero = 0; + if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) { logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno)); return false; } } + #endif #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST) { @@ -238,53 +263,66 @@ static bool setup_device(void) { } #endif - device_info = "Generic BSD tun device"; - break; - case DEVICE_TYPE_TUNIFHEAD: + device_info = "Generic BSD tun device"; + break; + + case DEVICE_TYPE_TUNIFHEAD: #ifdef TUNSIFHEAD { const int one = 1; + if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) { logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno)); return false; } } + #endif #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST) { - const int mode = IFF_BROADCAST | IFF_MULTICAST; - ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode)); + const int mode = IFF_BROADCAST | IFF_MULTICAST; + ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode)); } #endif - device_info = "Generic BSD tun device"; - break; - case DEVICE_TYPE_TAP: - if(routing_mode == RMODE_ROUTER) - overwrite_mac = true; - device_info = "Generic BSD tap device"; + device_info = "Generic BSD tun device"; + break; + + case DEVICE_TYPE_TAP: + if(routing_mode == RMODE_ROUTER) { + overwrite_mac = true; + } + + device_info = "Generic BSD tap device"; #ifdef TAPGIFNAME - { - struct ifreq ifr; - if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) { - if(iface) - free(iface); - iface = xstrdup(ifr.ifr_name); + { + struct ifreq ifr; + + if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) { + if(iface) { + free(iface); } + + iface = xstrdup(ifr.ifr_name); } - + } + #endif - break; + break; #ifdef ENABLE_TUNEMU - case DEVICE_TYPE_TUNEMU: - device_info = "BSD tunemu device"; - break; + + case DEVICE_TYPE_TUNEMU: + device_info = "BSD tunemu device"; + break; #endif } #ifdef SIOCGIFADDR - if(overwrite_mac) + + if(overwrite_mac) { ioctl(device_fd, SIOCGIFADDR, mymac.x); + } + #endif logger(LOG_INFO, "%s is a %s", device, device_info); @@ -295,12 +333,14 @@ static bool setup_device(void) { static void close_device(void) { switch(device_type) { #ifdef ENABLE_TUNEMU - case DEVICE_TYPE_TUNEMU: - tunemu_close(device_fd); - break; + + case DEVICE_TYPE_TUNEMU: + tunemu_close(device_fd); + break; #endif - default: - close(device_fd); + + default: + close(device_fd); } free(device); @@ -311,154 +351,165 @@ static bool read_packet(vpn_packet_t *packet) { int lenin; switch(device_type) { - case DEVICE_TYPE_TUN: + case DEVICE_TYPE_TUN: #ifdef ENABLE_TUNEMU - case DEVICE_TYPE_TUNEMU: - if(device_type == DEVICE_TYPE_TUNEMU) - lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14); - else + case DEVICE_TYPE_TUNEMU: + if(device_type == DEVICE_TYPE_TUNEMU) { + lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14); + } else #endif - lenin = read(device_fd, packet->data + 14, MTU - 14); + lenin = read(device_fd, packet->data + 14, MTU - 14); - if(lenin <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); - return false; - } + if(lenin <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); + return false; + } - switch(packet->data[14] >> 4) { - case 4: - packet->data[12] = 0x08; - packet->data[13] = 0x00; - break; - case 6: - packet->data[12] = 0x86; - packet->data[13] = 0xDD; - break; - default: - ifdebug(TRAFFIC) logger(LOG_ERR, - "Unknown IP version %d while reading packet from %s %s", - packet->data[14] >> 4, device_info, device); - return false; - } + switch(packet->data[14] >> 4) { + case 4: + packet->data[12] = 0x08; + packet->data[13] = 0x00; + break; - memset(packet->data, 0, 12); - packet->len = lenin + 14; + case 6: + packet->data[12] = 0x86; + packet->data[13] = 0xDD; break; - case DEVICE_TYPE_UTUN: - case DEVICE_TYPE_TUNIFHEAD: { - if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); - return false; - } + default: + ifdebug(TRAFFIC) logger(LOG_ERR, + "Unknown IP version %d while reading packet from %s %s", + packet->data[14] >> 4, device_info, device); + return false; + } - switch(packet->data[14] >> 4) { - case 4: - packet->data[12] = 0x08; - packet->data[13] = 0x00; - break; - case 6: - packet->data[12] = 0x86; - packet->data[13] = 0xDD; - break; - default: - ifdebug(TRAFFIC) logger(LOG_ERR, - "Unknown IP version %d while reading packet from %s %s", - packet->data[14] >> 4, device_info, device); - return false; - } + memset(packet->data, 0, 12); + packet->len = lenin + 14; + break; - memset(packet->data, 0, 12); - packet->len = lenin + 10; - break; + case DEVICE_TYPE_UTUN: + case DEVICE_TYPE_TUNIFHEAD: { + if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); + return false; } - case DEVICE_TYPE_TAP: - if((lenin = read(device_fd, packet->data, MTU)) <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); - return false; - } + switch(packet->data[14] >> 4) { + case 4: + packet->data[12] = 0x08; + packet->data[13] = 0x00; + break; - packet->len = lenin; + case 6: + packet->data[12] = 0x86; + packet->data[13] = 0xDD; break; default: + ifdebug(TRAFFIC) logger(LOG_ERR, + "Unknown IP version %d while reading packet from %s %s", + packet->data[14] >> 4, device_info, device); + return false; + } + + memset(packet->data, 0, 12); + packet->len = lenin + 10; + break; + } + + case DEVICE_TYPE_TAP: + if((lenin = read(device_fd, packet->data, MTU)) <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); return false; + } + + packet->len = lenin; + break; + + default: + return false; } - + device_total_in += packet->len; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", - packet->len, device_info); + packet->len, device_info); return true; } static bool write_packet(vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); switch(device_type) { - case DEVICE_TYPE_TUN: - if(write(device_fd, packet->data + 14, packet->len - 14) < 0) { - logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, - device, strerror(errno)); - return false; - } - break; + case DEVICE_TYPE_TUN: + if(write(device_fd, packet->data + 14, packet->len - 14) < 0) { + logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, + device, strerror(errno)); + return false; + } - case DEVICE_TYPE_UTUN: - case DEVICE_TYPE_TUNIFHEAD: { - int af = (packet->data[12] << 8) + packet->data[13]; - uint32_t type; - - switch (af) { - case 0x0800: - type = htonl(AF_INET); - break; - case 0x86DD: - type = htonl(AF_INET6); - break; - default: - ifdebug(TRAFFIC) logger(LOG_ERR, - "Unknown address family %x while writing packet to %s %s", - af, device_info, device); - return false; - } + break; - memcpy(packet->data + 10, &type, sizeof(type)); + case DEVICE_TYPE_UTUN: + case DEVICE_TYPE_TUNIFHEAD: { + int af = (packet->data[12] << 8) + packet->data[13]; + uint32_t type; - if(write(device_fd, packet->data + 10, packet->len - 10) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); - return false; - } - break; - } - - case DEVICE_TYPE_TAP: - if(write(device_fd, packet->data, packet->len) < 0) { - logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, - device, strerror(errno)); - return false; - } + switch(af) { + case 0x0800: + type = htonl(AF_INET); break; -#ifdef ENABLE_TUNEMU - case DEVICE_TYPE_TUNEMU: - if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) { - logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, - device, strerror(errno)); - return false; - } + case 0x86DD: + type = htonl(AF_INET6); break; -#endif default: + ifdebug(TRAFFIC) logger(LOG_ERR, + "Unknown address family %x while writing packet to %s %s", + af, device_info, device); + return false; + } + + memcpy(packet->data + 10, &type, sizeof(type)); + + if(write(device_fd, packet->data + 10, packet->len - 10) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, + strerror(errno)); + return false; + } + + break; + } + + case DEVICE_TYPE_TAP: + if(write(device_fd, packet->data, packet->len) < 0) { + logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, + device, strerror(errno)); return false; + } + + break; + +#ifdef ENABLE_TUNEMU + + case DEVICE_TYPE_TUNEMU: + if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) { + logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, + device, strerror(errno)); + return false; + } + + break; +#endif + + default: + return false; } device_total_out += packet->len; diff --git a/src/bsd/tunemu.c b/src/bsd/tunemu.c index f532b04..7ff6f72 100644 --- a/src/bsd/tunemu.c +++ b/src/bsd/tunemu.c @@ -1,20 +1,20 @@ /* * tunemu - Tun device emulation for Darwin * Copyright (C) 2009 Friedrich Schöller - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ #include "tunemu.h" @@ -36,37 +36,34 @@ #define PPPPROTO_CTL 1 -#define PPP_IP 0x21 -#define PPP_IPV6 0x57 +#define PPP_IP 0x21 +#define PPP_IPV6 0x57 #define SC_LOOP_TRAFFIC 0x00000200 -#define PPPIOCNEWUNIT _IOWR('t', 62, int) -#define PPPIOCSFLAGS _IOW('t', 89, int) -#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) -#define PPPIOCATTCHAN _IOW('t', 56, int) -#define PPPIOCGCHAN _IOR('t', 55, int) -#define PPPIOCCONNECT _IOW('t', 58, int) -#define PPPIOCGUNIT _IOR('t', 86, int) +#define PPPIOCNEWUNIT _IOWR('t', 62, int) +#define PPPIOCSFLAGS _IOW('t', 89, int) +#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) +#define PPPIOCATTCHAN _IOW('t', 56, int) +#define PPPIOCGCHAN _IOR('t', 55, int) +#define PPPIOCCONNECT _IOW('t', 58, int) +#define PPPIOCGUNIT _IOR('t', 86, int) -struct sockaddr_ppp -{ +struct sockaddr_ppp { u_int8_t ppp_len; u_int8_t ppp_family; u_int16_t ppp_proto; u_int32_t ppp_cookie; }; -enum NPmode -{ +enum NPmode { NPMODE_PASS, - NPMODE_DROP, - NPMODE_ERROR, - NPMODE_QUEUE + NPMODE_DROP, + NPMODE_ERROR, + NPMODE_QUEUE }; -struct npioctl -{ +struct npioctl { int protocol; enum NPmode mode; }; @@ -83,58 +80,55 @@ static pcap_t *pcap = NULL; static int data_buffer_length = 0; static char *data_buffer = NULL; -static void tun_error(char *format, ...) -{ +static void tun_error(char *format, ...) { va_list vl; va_start(vl, format); vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl); va_end(vl); } -static void tun_noerror() -{ +static void tun_noerror() { *tunemu_error = 0; } -static void closeall() -{ - int fd = getdtablesize(); - while (fd--) +static void closeall() { + int fd = getdtablesize(); + + while(fd--) { close(fd); + } - open("/dev/null", O_RDWR, 0); - dup(0); - dup(0); + open("/dev/null", O_RDWR, 0); + dup(0); + dup(0); } -static int ppp_load_kext() -{ +static int ppp_load_kext() { int pid = fork(); - if (pid < 0) - { + + if(pid < 0) { tun_error("fork for ppp kext: %s", strerror(errno)); return -1; } - if (pid == 0) - { + if(pid == 0) { closeall(); execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL); exit(1); } int status; - while (waitpid(pid, &status, 0) < 0) - { - if (errno == EINTR) + + while(waitpid(pid, &status, 0) < 0) { + if(errno == EINTR) { continue; + } tun_error("waitpid for ppp kext: %s", strerror(errno)); return -1; } - if (WEXITSTATUS(status) != 0) - { + if(WEXITSTATUS(status) != 0) { tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH); return -1; } @@ -143,74 +137,73 @@ static int ppp_load_kext() return 0; } -static int ppp_new_instance() -{ +static int ppp_new_instance() { // create ppp socket - int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); - if (ppp_sockfd < 0) - { - if (ppp_load_kext() < 0) + int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); + + if(ppp_sockfd < 0) { + if(ppp_load_kext() < 0) { return -1; + } ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); - if (ppp_sockfd < 0) - { + + if(ppp_sockfd < 0) { tun_error("creating ppp socket: %s", strerror(errno)); return -1; } } // connect to ppp procotol - struct sockaddr_ppp pppaddr; - pppaddr.ppp_len = sizeof(struct sockaddr_ppp); - pppaddr.ppp_family = AF_PPP; - pppaddr.ppp_proto = PPPPROTO_CTL; - pppaddr.ppp_cookie = 0; - if (connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) - { + struct sockaddr_ppp pppaddr; + pppaddr.ppp_len = sizeof(struct sockaddr_ppp); + pppaddr.ppp_family = AF_PPP; + pppaddr.ppp_proto = PPPPROTO_CTL; + pppaddr.ppp_cookie = 0; + + if(connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) { tun_error("connecting ppp socket: %s", strerror(errno)); close(ppp_sockfd); return -1; - } + } tun_noerror(); return ppp_sockfd; } -static int ppp_new_unit(int *unit_number) -{ +static int ppp_new_unit(int *unit_number) { int fd = ppp_new_instance(); - if (fd < 0) + + if(fd < 0) { return -1; + } // create ppp unit - if (ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) - { + if(ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) { tun_error("creating ppp unit: %s", strerror(errno)); close(fd); return -1; - } + } tun_noerror(); return fd; } -static int ppp_setup_unit(int unit_fd) -{ +static int ppp_setup_unit(int unit_fd) { // send traffic to program int flags = SC_LOOP_TRAFFIC; - if (ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) - { + + if(ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) { tun_error("setting ppp loopback mode: %s", strerror(errno)); return -1; - } + } // allow packets struct npioctl npi; npi.protocol = PPP_IP; npi.mode = NPMODE_PASS; - if (ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) - { + + if(ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) { tun_error("starting ppp unit: %s", strerror(errno)); return -1; } @@ -219,10 +212,8 @@ static int ppp_setup_unit(int unit_fd) return 0; } -static int open_pcap() -{ - if (pcap != NULL) - { +static int open_pcap() { + if(pcap != NULL) { pcap_use_count++; return 0; } @@ -231,8 +222,7 @@ static int open_pcap() pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf); pcap_use_count = 1; - if (pcap == NULL) - { + if(pcap == NULL) { tun_error("opening pcap: %s", errbuf); return -1; } @@ -241,59 +231,57 @@ static int open_pcap() return 0; } -static void close_pcap() -{ - if (pcap == NULL) +static void close_pcap() { + if(pcap == NULL) { return; + } pcap_use_count--; - if (pcap_use_count == 0) - { + + if(pcap_use_count == 0) { pcap_close(pcap); pcap = NULL; } } -static void allocate_data_buffer(int size) -{ - if (data_buffer_length < size) - { +static void allocate_data_buffer(int size) { + if(data_buffer_length < size) { free(data_buffer); data_buffer_length = size; data_buffer = malloc(data_buffer_length); } } -static void make_device_name(tunemu_device device, int unit_number) -{ +static void make_device_name(tunemu_device device, int unit_number) { snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number); } -static int check_device_name(tunemu_device device) -{ - if (strlen(device) < 4) +static int check_device_name(tunemu_device device) { + if(strlen(device) < 4) { return -1; + } int unit_number = atoi(device + 3); - if (unit_number < 0 || unit_number > 999) + + if(unit_number < 0 || unit_number > 999) { return -1; + } tunemu_device compare; make_device_name(compare, unit_number); - if (strcmp(device, compare) != 0) + if(strcmp(device, compare) != 0) { return -1; + } return 0; } -int tunemu_open(tunemu_device device) -{ +int tunemu_open(tunemu_device device) { int ppp_unit_number = -1; - if (device[0] != 0) - { - if (check_device_name(device) < 0) - { + + if(device[0] != 0) { + if(check_device_name(device) < 0) { tun_error("invalid device name \"%s\"", device); return -1; } @@ -302,17 +290,17 @@ int tunemu_open(tunemu_device device) } int ppp_unit_fd = ppp_new_unit(&ppp_unit_number); - if (ppp_unit_fd < 0) + + if(ppp_unit_fd < 0) { return -1; + } - if (ppp_setup_unit(ppp_unit_fd) < 0) - { + if(ppp_setup_unit(ppp_unit_fd) < 0) { close(ppp_unit_fd); return -1; } - if (open_pcap() < 0) - { + if(open_pcap() < 0) { close(ppp_unit_fd); return -1; } @@ -322,39 +310,40 @@ int tunemu_open(tunemu_device device) return ppp_unit_fd; } -int tunemu_close(int ppp_sockfd) -{ +int tunemu_close(int ppp_sockfd) { int ret = close(ppp_sockfd); - if (ret == 0) + if(ret == 0) { close_pcap(); + } return ret; } -int tunemu_read(int ppp_sockfd, char *buffer, int length) -{ +int tunemu_read(int ppp_sockfd, char *buffer, int length) { allocate_data_buffer(length + 2); length = read(ppp_sockfd, data_buffer, length + 2); - if (length < 0) - { + + if(length < 0) { tun_error("reading packet: %s", strerror(errno)); return length; } + tun_noerror(); length -= 2; - if (length < 0) + + if(length < 0) { return 0; + } memcpy(buffer, data_buffer + 2, length); return length; } -int tunemu_write(int ppp_sockfd, char *buffer, int length) -{ +int tunemu_write(int ppp_sockfd, char *buffer, int length) { allocate_data_buffer(length + 4); data_buffer[0] = 0x02; @@ -364,23 +353,25 @@ int tunemu_write(int ppp_sockfd, char *buffer, int length) memcpy(data_buffer + 4, buffer, length); - if (pcap == NULL) - { + if(pcap == NULL) { tun_error("pcap not open"); return -1; } length = pcap_inject(pcap, data_buffer, length + 4); - if (length < 0) - { + + if(length < 0) { tun_error("injecting packet: %s", pcap_geterr(pcap)); return length; } + tun_noerror(); length -= 4; - if (length < 0) + + if(length < 0) { return 0; + } return length; } diff --git a/src/bsd/tunemu.h b/src/bsd/tunemu.h index 42b1785..e0452a8 100644 --- a/src/bsd/tunemu.h +++ b/src/bsd/tunemu.h @@ -1,20 +1,20 @@ /* * tunemu - Tun device emulation for Darwin * Copyright (C) 2009 Friedrich Schöller - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ #ifndef TUNEMU_H diff --git a/src/conf.c b/src/conf.c index 82bc521..3289c58 100644 --- a/src/conf.c +++ b/src/conf.c @@ -4,7 +4,7 @@ 1998-2005 Ivo Timmermans 2000-2014 Guus Sliepen 2010-2011 Julien Muchembled - 2000 Cris van Pelt + 2000 Cris van Pelt This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,18 +28,18 @@ #include "conf.h" #include "list.h" #include "logger.h" -#include "netutl.h" /* for str2address */ +#include "netutl.h" /* for str2address */ #include "protocol.h" -#include "utils.h" /* for cp */ +#include "utils.h" /* for cp */ #include "xalloc.h" avl_tree_t *config_tree; -int pinginterval = 0; /* seconds between pings */ -int pingtimeout = 0; /* seconds to wait for response */ -char *confbase = NULL; /* directory in which all config files are */ -char *netname = NULL; /* name of the vpn network */ -list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */ +int pinginterval = 0; /* seconds between pings */ +int pingtimeout = 0; /* seconds to wait for response */ +char *confbase = NULL; /* directory in which all config files are */ +char *netname = NULL; /* name of the vpn network */ +list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */ static int config_compare(const config_t *a, const config_t *b) { @@ -47,27 +47,31 @@ static int config_compare(const config_t *a, const config_t *b) { result = strcasecmp(a->variable, b->variable); - if(result) + if(result) { return result; + } /* give priority to command line options */ result = !b->file - !a->file; - if (result) + + if(result) { return result; + } result = a->line - b->line; - if(result) + if(result) { return result; - else + } else { return a->file ? strcmp(a->file, b->file) : 0; + } } -void init_configuration(avl_tree_t ** config_tree) { +void init_configuration(avl_tree_t **config_tree) { *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config); } -void exit_configuration(avl_tree_t ** config_tree) { +void exit_configuration(avl_tree_t **config_tree) { avl_delete_tree(*config_tree); *config_tree = NULL; } @@ -77,14 +81,17 @@ config_t *new_config(void) { } void free_config(config_t *cfg) { - if(cfg->variable) + if(cfg->variable) { free(cfg->variable); + } - if(cfg->value) + if(cfg->value) { free(cfg->value); + } - if(cfg->file) + if(cfg->file) { free(cfg->file); + } free(cfg); } @@ -102,11 +109,13 @@ config_t *lookup_config(const avl_tree_t *config_tree, char *variable) { found = avl_search_closest_greater(config_tree, &cfg); - if(!found) + if(!found) { return NULL; + } - if(strcasecmp(found->variable, variable)) + if(strcasecmp(found->variable, variable)) { return NULL; + } return found; } @@ -121,8 +130,9 @@ config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) if(node->next) { found = node->next->data; - if(!strcasecmp(found->variable, cfg->variable)) + if(!strcasecmp(found->variable, cfg->variable)) { return found; + } } } @@ -130,8 +140,9 @@ config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) } bool get_config_bool(const config_t *cfg, bool *result) { - if(!cfg) + if(!cfg) { return false; + } if(!strcasecmp(cfg->value, "yes")) { *result = true; @@ -142,27 +153,30 @@ bool get_config_bool(const config_t *cfg, bool *result) { } logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + cfg->variable, cfg->file, cfg->line); return false; } bool get_config_int(const config_t *cfg, int *result) { - if(!cfg) + if(!cfg) { return false; + } - if(sscanf(cfg->value, "%d", result) == 1) + if(sscanf(cfg->value, "%d", result) == 1) { return true; + } logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + cfg->variable, cfg->file, cfg->line); return false; } bool get_config_string(const config_t *cfg, char **result) { - if(!cfg) + if(!cfg) { return false; + } *result = xstrdup(cfg->value); @@ -172,8 +186,9 @@ bool get_config_string(const config_t *cfg, char **result) { bool get_config_address(const config_t *cfg, struct addrinfo **result) { struct addrinfo *ai; - if(!cfg) + if(!cfg) { return false; + } ai = str2addrinfo(cfg->value, NULL, 0); @@ -183,31 +198,32 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) { } logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + cfg->variable, cfg->file, cfg->line); return false; } -bool get_config_subnet(const config_t *cfg, subnet_t ** result) { +bool get_config_subnet(const config_t *cfg, subnet_t **result) { subnet_t subnet = {NULL}; - if(!cfg) + if(!cfg) { return false; + } if(!str2net(&subnet, cfg->value)) { logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + cfg->variable, cfg->file, cfg->line); return false; } /* Teach newbies what subnets are... */ if(((subnet.type == SUBNET_IPV4) - && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t))) - || ((subnet.type == SUBNET_IPV6) - && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) { + && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t))) + || ((subnet.type == SUBNET_IPV6) + && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) { logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + cfg->variable, cfg->file, cfg->line); return false; } @@ -219,26 +235,31 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) { /* Read exactly one line and strip the trailing newline if any. */ -static char *readline(FILE * fp, char *buf, size_t buflen) { +static char *readline(FILE *fp, char *buf, size_t buflen) { char *newline = NULL; char *p; - if(feof(fp)) + if(feof(fp)) { return NULL; + } p = fgets(buf, buflen, fp); - if(!p) + if(!p) { return NULL; + } newline = strchr(p, '\n'); - if(!newline) + if(!newline) { return buf; + } + + *newline = '\0'; /* kill newline */ - *newline = '\0'; /* kill newline */ - if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */ + if(newline > p && newline[-1] == '\r') { /* and carriage return if necessary */ newline[-1] = '\0'; + } return buf; } @@ -250,26 +271,32 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) { variable = value = line; eol = line + strlen(line); - while(strchr("\t ", *--eol)) + + while(strchr("\t ", *--eol)) { *eol = '\0'; + } len = strcspn(value, "\t ="); value += len; value += strspn(value, "\t "); + if(*value == '=') { value++; value += strspn(value, "\t "); } + variable[len] = '\0'; if(!*value) { const char err[] = "No value for variable"; - if (fname) + + if(fname) logger(LOG_ERR, "%s `%s' on line %d while reading config file %s", - err, variable, lineno, fname); + err, variable, lineno, fname); else logger(LOG_ERR, "%s `%s' in command line option %d", - err, variable, lineno); + err, variable, lineno); + return NULL; } @@ -306,30 +333,38 @@ bool read_config_file(avl_tree_t *config_tree, const char *fname) { line = readline(fp, buffer, sizeof(buffer)); if(!line) { - if(feof(fp)) + if(feof(fp)) { result = true; + } + break; } lineno++; - if(!*line || *line == '#') + if(!*line || *line == '#') { continue; + } if(ignore) { - if(!strncmp(line, "-----END", 8)) + if(!strncmp(line, "-----END", 8)) { ignore = false; + } + continue; } - + if(!strncmp(line, "-----BEGIN", 10)) { ignore = true; continue; } cfg = parse_config_line(line, fname, lineno); - if (!cfg) + + if(!cfg) { break; + } + config_add(config_tree, cfg); } @@ -345,12 +380,14 @@ void read_config_options(avl_tree_t *config_tree, const char *prefix) { const config_t *cfg = node->data; if(!prefix) { - if(strchr(cfg->variable, '.')) + if(strchr(cfg->variable, '.')) { continue; + } } else { if(strncmp(prefix, cfg->variable, prefix_len) || - cfg->variable[prefix_len] != '.') + cfg->variable[prefix_len] != '.') { continue; + } } config_t *new = new_config(); @@ -380,23 +417,27 @@ bool read_server_config(void) { x = read_config_file(config_tree, fname); // We will try to read the conf files in the "conf.d" dir - if (x) { + if(x) { char dname[PATH_MAX]; snprintf(dname, sizeof(dname), "%s/conf.d", confbase); - DIR *dir = opendir (dname); + DIR *dir = opendir(dname); + // If we can find this dir - if (dir) { + if(dir) { struct dirent *ep; + // We list all the files in it - while (x && (ep = readdir (dir))) { + while(x && (ep = readdir(dir))) { size_t l = strlen(ep->d_name); + // And we try to read the ones that end with ".conf" - if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) { + if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) { snprintf(fname, sizeof(fname), "%s/%s", dname, ep->d_name); x = read_config_file(config_tree, fname); } } - closedir (dir); + + closedir(dir); } } @@ -426,34 +467,38 @@ static void disable_old_keys(const char *filename) { FILE *r, *w; r = fopen(filename, "r"); - if(!r) + + if(!r) { return; + } snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename); w = fopen(tmpfile, "w"); while(fgets(buf, sizeof(buf), r)) { - if(!strncmp(buf, "-----BEGIN RSA", 14)) { + if(!strncmp(buf, "-----BEGIN RSA", 14)) { buf[11] = 'O'; buf[12] = 'L'; buf[13] = 'D'; disabled = true; - } - else if(!strncmp(buf, "-----END RSA", 12)) { + } else if(!strncmp(buf, "-----END RSA", 12)) { buf[ 9] = 'O'; buf[10] = 'L'; buf[11] = 'D'; disabled = true; } + if(w && fputs(buf, w) < 0) { disabled = false; break; } } - if(w) + if(w) { fclose(w); + } + fclose(r); if(!w && disabled) { @@ -466,9 +511,11 @@ static void disable_old_keys(const char *filename) { // We cannot atomically replace files on Windows. char bakfile[PATH_MAX] = ""; snprintf(bakfile, sizeof(bakfile), "%s.bak", filename); + if(rename(filename, bakfile) || rename(tmpfile, filename)) { rename(bakfile, filename); #else + if(rename(tmpfile, filename)) { #endif fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); @@ -499,25 +546,29 @@ FILE *ask_and_open(const char *filename, const char *what) { } else { /* Ask for a file and/or directory name. */ fprintf(stdout, "Please enter a file to save %s to [%s]: ", - what, filename); + what, filename); fflush(stdout); fn = readline(stdin, line, sizeof(line)); if(!fn) { fprintf(stderr, "Error while reading stdin: %s\n", - strerror(errno)); + strerror(errno)); return NULL; } if(!strlen(fn)) /* User just pressed enter. */ + { fn = filename; + } } #ifdef HAVE_MINGW + if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) { #else + if(fn[0] != '/') { #endif /* The directory is a relative path or a filename. */ @@ -526,7 +577,7 @@ FILE *ask_and_open(const char *filename, const char *what) { fn = abspath; } - umask(0077); /* Disallow everything for group and other */ + umask(0077); /* Disallow everything for group and other */ disable_old_keys(fn); @@ -536,7 +587,7 @@ FILE *ask_and_open(const char *filename, const char *what) { if(!r) { fprintf(stderr, "Error opening file `%s': %s\n", - fn, strerror(errno)); + fn, strerror(errno)); return NULL; } diff --git a/src/conf.h b/src/conf.h index 1be18c3..cef5d77 100644 --- a/src/conf.h +++ b/src/conf.h @@ -46,7 +46,7 @@ extern list_t *cmdline_conf; extern void init_configuration(avl_tree_t **); extern void exit_configuration(avl_tree_t **); -extern config_t *new_config(void) __attribute__ ((__malloc__)); +extern config_t *new_config(void) __attribute__((__malloc__)); extern void free_config(config_t *); extern void config_add(avl_tree_t *, config_t *); extern config_t *lookup_config(const avl_tree_t *, char *); diff --git a/src/connection.c b/src/connection.c index 46b11c8..38b3ccf 100644 --- a/src/connection.c +++ b/src/connection.c @@ -28,7 +28,7 @@ #include "utils.h" #include "xalloc.h" -avl_tree_t *connection_tree; /* Meta connections */ +avl_tree_t *connection_tree; /* Meta connections */ connection_t *everyone; static int connection_compare(const connection_t *a, const connection_t *b) { @@ -52,8 +52,9 @@ connection_t *new_connection(void) { c = xmalloc_and_zero(sizeof(connection_t)); - if(!c) + if(!c) { return NULL; + } gettimeofday(&c->start, NULL); @@ -118,8 +119,9 @@ void free_connection(connection_t *c) { free(c->name); free(c->hostname); - if(c->config_tree) + if(c->config_tree) { exit_configuration(&c->config_tree); + } free(c); } @@ -141,8 +143,8 @@ void dump_connections(void) { for(node = connection_tree->head; node; node = node->next) { c = node->data; logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d", - c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)), - c->outbufsize, c->outbufstart, c->outbuflen); + c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)), + c->outbufsize, c->outbufstart, c->outbuflen); } logger(LOG_DEBUG, "End of connections."); diff --git a/src/connection.h b/src/connection.h index 206d520..1cc9818 100644 --- a/src/connection.h +++ b/src/connection.h @@ -26,23 +26,23 @@ #include "avl_tree.h" -#define OPTION_INDIRECT 0x0001 -#define OPTION_TCPONLY 0x0002 -#define OPTION_PMTU_DISCOVERY 0x0004 -#define OPTION_CLAMP_MSS 0x0008 +#define OPTION_INDIRECT 0x0001 +#define OPTION_TCPONLY 0x0002 +#define OPTION_PMTU_DISCOVERY 0x0004 +#define OPTION_CLAMP_MSS 0x0008 typedef struct connection_status_t { - unsigned int pinged:1; /* sent ping */ - unsigned int active:1; /* 1 if active.. */ - unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */ - unsigned int unused_termreq:1; /* the termination of this connection was requested */ - unsigned int remove:1; /* Set to 1 if you want this connection removed */ - unsigned int timeout:1; /* 1 if gotten timeout */ - unsigned int encryptout:1; /* 1 if we can encrypt outgoing traffic */ - unsigned int decryptin:1; /* 1 if we have to decrypt incoming traffic */ - unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */ - unsigned int proxy_passed:1; /* 1 if we are connecting via a proxy and we have finished talking with it */ - unsigned int unused:22; + unsigned int pinged: 1; /* sent ping */ + unsigned int active: 1; /* 1 if active.. */ + unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */ + unsigned int unused_termreq: 1; /* the termination of this connection was requested */ + unsigned int remove: 1; /* Set to 1 if you want this connection removed */ + unsigned int timeout: 1; /* 1 if gotten timeout */ + unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */ + unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */ + unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */ + unsigned int proxy_passed: 1; /* 1 if we are connecting via a proxy and we have finished talking with it */ + unsigned int unused: 22; } connection_status_t; #include "edge.h" @@ -50,57 +50,57 @@ typedef struct connection_status_t { #include "node.h" typedef struct connection_t { - char *name; /* name he claims to have */ - - union sockaddr_t address; /* his real (internet) ip */ - char *hostname; /* the hostname of its real ip */ - int protocol_version; /* used protocol */ - - int socket; /* socket used for this connection */ - uint32_t options; /* options for this connection */ - connection_status_t status; /* status info */ - int estimated_weight; /* estimation for the weight of the edge for this connection */ - struct timeval start; /* time this connection was started, used for above estimation */ - struct outgoing_t *outgoing; /* used to keep track of outgoing connections */ - - struct node_t *node; /* node associated with the other end */ - struct edge_t *edge; /* edge associated with this connection */ - - RSA *rsa_key; /* his public/private key */ - const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */ - const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */ - EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */ - EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */ + char *name; /* name he claims to have */ + + union sockaddr_t address; /* his real (internet) ip */ + char *hostname; /* the hostname of its real ip */ + int protocol_version; /* used protocol */ + + int socket; /* socket used for this connection */ + uint32_t options; /* options for this connection */ + connection_status_t status; /* status info */ + int estimated_weight; /* estimation for the weight of the edge for this connection */ + struct timeval start; /* time this connection was started, used for above estimation */ + struct outgoing_t *outgoing; /* used to keep track of outgoing connections */ + + struct node_t *node; /* node associated with the other end */ + struct edge_t *edge; /* edge associated with this connection */ + + RSA *rsa_key; /* his public/private key */ + const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */ + const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */ + EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */ + EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */ uint64_t inbudget; /* Encrypted bytes send budget */ uint64_t outbudget; /* Encrypted bytes receive budget */ - char *inkey; /* His symmetric meta key + iv */ - char *outkey; /* Our symmetric meta key + iv */ - int inkeylength; /* Length of his key + iv */ - int outkeylength; /* Length of our key + iv */ + char *inkey; /* His symmetric meta key + iv */ + char *outkey; /* Our symmetric meta key + iv */ + int inkeylength; /* Length of his key + iv */ + int outkeylength; /* Length of our key + iv */ const EVP_MD *indigest; const EVP_MD *outdigest; int inmaclength; int outmaclength; int incompression; int outcompression; - char *mychallenge; /* challenge we received from him */ - char *hischallenge; /* challenge we sent to him */ + char *mychallenge; /* challenge we received from him */ + char *hischallenge; /* challenge we sent to him */ - char buffer[MAXBUFSIZE]; /* metadata input buffer */ - int buflen; /* bytes read into buffer */ - int reqlen; /* length of incoming request */ - int tcplen; /* length of incoming TCPpacket */ - int allow_request; /* defined if there's only one request possible */ + char buffer[MAXBUFSIZE]; /* metadata input buffer */ + int buflen; /* bytes read into buffer */ + int reqlen; /* length of incoming request */ + int tcplen; /* length of incoming TCPpacket */ + int allow_request; /* defined if there's only one request possible */ - char *outbuf; /* metadata output buffer */ - int outbufstart; /* index of first meaningful byte in output buffer */ - int outbuflen; /* number of meaningful bytes in output buffer */ - int outbufsize; /* number of bytes allocated to output buffer */ + char *outbuf; /* metadata output buffer */ + int outbufstart; /* index of first meaningful byte in output buffer */ + int outbuflen; /* number of meaningful bytes in output buffer */ + int outbufsize; /* number of bytes allocated to output buffer */ - time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */ - time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */ + time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */ + time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */ - avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */ + avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */ } connection_t; extern avl_tree_t *connection_tree; @@ -108,7 +108,7 @@ extern connection_t *everyone; extern void init_connections(void); extern void exit_connections(void); -extern connection_t *new_connection(void) __attribute__ ((__malloc__)); +extern connection_t *new_connection(void) __attribute__((__malloc__)); extern void free_connection(connection_t *); extern void free_connection_partially(connection_t *); extern void connection_add(connection_t *); diff --git a/src/cygwin/device.c b/src/cygwin/device.c index 9fce9be..3a242bf 100644 --- a/src/cygwin/device.c +++ b/src/cygwin/device.c @@ -61,8 +61,9 @@ static bool setup_device(void) { get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Interface"), &iface); - if(device && iface) + if(device && iface) { logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); + } /* Open registry and look for network adapters */ @@ -71,44 +72,51 @@ static bool setup_device(void) { return false; } - for (i = 0; ; i++) { + for(i = 0; ; i++) { len = sizeof(adapterid); - if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) + + if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) { break; + } /* Find out more about this adapter */ snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) { continue; + } len = sizeof(adaptername); err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len); RegCloseKey(key2); - if(err) + if(err) { continue; + } if(device) { if(!strcmp(device, adapterid)) { found = true; break; - } else + } else { continue; + } } if(iface) { if(!strcmp(iface, adaptername)) { found = true; break; - } else + } else { continue; + } } snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); + if(device_handle != INVALID_HANDLE_VALUE) { CloseHandle(device_handle); found = true; @@ -123,14 +131,16 @@ static bool setup_device(void) { return false; } - if(!device) + if(!device) { device = xstrdup(adapterid); + } - if(!iface) + if(!iface) { iface = xstrdup(adaptername); + } snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); - + /* Now we are going to open this device twice: once for reading and once for writing. We do this because apparently it isn't possible to check for activity in the select() loop. Furthermore I don't really know how to do it the "Windows" way. */ @@ -141,9 +151,9 @@ static bool setup_device(void) { } /* The parent opens the tap device for writing. */ - - device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); - + + device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); + if(device_handle == INVALID_HANDLE_VALUE) { logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError())); return false; @@ -174,7 +184,7 @@ static bool setup_device(void) { if(!reader_pid) { /* The child opens the tap device for reading, blocking. It passes everything it reads to the socket. */ - + char buf[MTU]; long lenin; @@ -205,6 +215,7 @@ static bool setup_device(void) { } read(device_fd, &gelukt, 1); + if(gelukt != 1) { logger(LOG_DEBUG, "Tap reader failed!"); return false; @@ -233,16 +244,16 @@ static bool read_packet(vpn_packet_t *packet) { if((lenin = read(sp[0], packet->data, MTU)) <= 0) { logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); + device, strerror(errno)); return false; } - + packet->len = lenin; device_total_in += packet->len; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, - device_info); + device_info); return true; } @@ -251,9 +262,9 @@ static bool write_packet(vpn_packet_t *packet) { long lenout; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); - if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) { + if(!WriteFile(device_handle, packet->data, packet->len, &lenout, NULL)) { logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); return false; } diff --git a/src/dropin.c b/src/dropin.c index 49d5662..93511f1 100644 --- a/src/dropin.c +++ b/src/dropin.c @@ -25,7 +25,7 @@ #ifndef HAVE_DAEMON /* Replacement for the daemon() function. - + The daemon() function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons. @@ -50,8 +50,9 @@ int daemon(int nochdir, int noclose) { } /* If we are the parent, terminate */ - if(pid) + if(pid) { exit(0); + } /* Detach by becoming the new process group leader */ if(setsid() < 0) { @@ -109,8 +110,9 @@ int vasprintf(char **buf, const char *fmt, va_list ap) { buf[len - 1] = 0; va_end(aq); - if(status >= 0) + if(status >= 0) { *buf = xrealloc(*buf, status + 1); + } if(status > len - 1) { len = status; diff --git a/src/edge.c b/src/edge.c index e42dbd1..c30d6cc 100644 --- a/src/edge.c +++ b/src/edge.c @@ -28,7 +28,7 @@ #include "utils.h" #include "xalloc.h" -avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */ +avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */ static int edge_compare(const edge_t *a, const edge_t *b) { return strcmp(a->to->name, b->to->name); @@ -39,13 +39,15 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b) { result = a->weight - b->weight; - if(result) + if(result) { return result; + } result = strcmp(a->from->name, b->from->name); - if(result) + if(result) { return result; + } return strcmp(a->to->name, b->to->name); } @@ -84,13 +86,15 @@ void edge_add(edge_t *e) { e->reverse = lookup_edge(e->to, e->from); - if(e->reverse) + if(e->reverse) { e->reverse->reverse = e; + } } void edge_del(edge_t *e) { - if(e->reverse) + if(e->reverse) { e->reverse->reverse = NULL; + } avl_delete(edge_weight_tree, e); avl_delete(e->from->edge_tree, e); @@ -98,7 +102,7 @@ void edge_del(edge_t *e) { edge_t *lookup_edge(node_t *from, node_t *to) { edge_t v; - + v.from = from; v.to = to; @@ -115,11 +119,12 @@ void dump_edges(void) { for(node = node_tree->head; node; node = node->next) { n = node->data; + for(node2 = n->edge_tree->head; node2; node2 = node2->next) { e = node2->data; address = sockaddr2hostname(&e->address); logger(LOG_DEBUG, " %s to %s at %s options %x weight %d", - e->from->name, e->to->name, address, e->options, e->weight); + e->from->name, e->to->name, address, e->options, e->weight); free(address); } } diff --git a/src/edge.h b/src/edge.h index ad92641..ef4feef 100644 --- a/src/edge.h +++ b/src/edge.h @@ -31,20 +31,20 @@ typedef struct edge_t { struct node_t *to; sockaddr_t address; - uint32_t options; /* options turned on for this edge */ - int weight; /* weight of this edge */ + uint32_t options; /* options turned on for this edge */ + int weight; /* weight of this edge */ - struct connection_t *connection; /* connection associated with this edge, if available */ - struct edge_t *reverse; /* edge in the opposite direction, if available */ + struct connection_t *connection; /* connection associated with this edge, if available */ + struct edge_t *reverse; /* edge in the opposite direction, if available */ } edge_t; -extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */ +extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */ extern void init_edges(void); extern void exit_edges(void); -extern edge_t *new_edge(void) __attribute__ ((__malloc__)); +extern edge_t *new_edge(void) __attribute__((__malloc__)); extern void free_edge(edge_t *); -extern avl_tree_t *new_edge_tree(void) __attribute__ ((__malloc__)); +extern avl_tree_t *new_edge_tree(void) __attribute__((__malloc__)); extern void free_edge_tree(avl_tree_t *); extern void edge_add(edge_t *); extern void edge_del(edge_t *); diff --git a/src/ethernet.h b/src/ethernet.h index eea78dd..32f5553 100644 --- a/src/ethernet.h +++ b/src/ethernet.h @@ -50,7 +50,7 @@ struct ether_header { uint8_t ether_dhost[ETH_ALEN]; uint8_t ether_shost[ETH_ALEN]; uint16_t ether_type; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #endif #ifndef HAVE_STRUCT_ARPHDR @@ -58,17 +58,17 @@ struct arphdr { uint16_t ar_hrd; uint16_t ar_pro; uint8_t ar_hln; - uint8_t ar_pln; - uint16_t ar_op; -} __attribute__ ((__packed__)); + uint8_t ar_pln; + uint16_t ar_op; +} __attribute__((__packed__)); -#define ARPOP_REQUEST 1 -#define ARPOP_REPLY 2 -#define ARPOP_RREQUEST 3 -#define ARPOP_RREPLY 4 -#define ARPOP_InREQUEST 8 -#define ARPOP_InREPLY 9 -#define ARPOP_NAK 10 +#define ARPOP_REQUEST 1 +#define ARPOP_REPLY 2 +#define ARPOP_RREQUEST 3 +#define ARPOP_RREPLY 4 +#define ARPOP_InREQUEST 8 +#define ARPOP_InREPLY 9 +#define ARPOP_NAK 10 #endif #ifndef HAVE_STRUCT_ETHER_ARP @@ -78,7 +78,7 @@ struct ether_arp { uint8_t arp_spa[4]; uint8_t arp_tha[ETH_ALEN]; uint8_t arp_tpa[4]; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #define arp_hrd ea_hdr.ar_hrd #define arp_pro ea_hdr.ar_pro #define arp_hln ea_hdr.ar_hln diff --git a/src/event.c b/src/event.c index 89ee022..85b18f7 100644 --- a/src/event.c +++ b/src/event.c @@ -31,11 +31,13 @@ extern time_t now; static int id; static int event_compare(const event_t *a, const event_t *b) { - if(a->time > b->time) + if(a->time > b->time) { return 1; + } - if(a->time < b->time) + if(a->time < b->time) { return -1; + } return a->id - b->id; } @@ -55,18 +57,21 @@ void expire_events(void) { /* * Make all events appear expired by substracting the difference between - * the expiration time of the last event and the current time. + * the expiration time of the last event and the current time. */ - if(!event_tree->tail) + if(!event_tree->tail) { return; + } event = event_tree->tail->data; - if(event->time <= now) + + if(event->time <= now) { return; + } diff = event->time - now; - + for(node = event_tree->head; node; node = node->next) { event = node->data; event->time -= diff; @@ -108,7 +113,9 @@ event_t *get_expired_event(void) { } event_t *peek_next_event(void) { - if (event_tree->head) + if(event_tree->head) { return event_tree->head->data; + } + return NULL; } diff --git a/src/event.h b/src/event.h index d1ca9d2..c6bd207 100644 --- a/src/event.h +++ b/src/event.h @@ -37,7 +37,7 @@ typedef struct event { extern void init_events(void); extern void exit_events(void); extern void expire_events(void); -extern event_t *new_event(void) __attribute__ ((__malloc__)); +extern event_t *new_event(void) __attribute__((__malloc__)); extern void free_event(event_t *); extern void event_add(event_t *); extern void event_del(event_t *); diff --git a/src/fake-getaddrinfo.c b/src/fake-getaddrinfo.c index 10672b7..231bd5c 100644 --- a/src/fake-getaddrinfo.c +++ b/src/fake-getaddrinfo.c @@ -17,24 +17,25 @@ #include "xalloc.h" #if !HAVE_DECL_GAI_STRERROR -char *gai_strerror(int ecode) -{ - switch (ecode) { - case EAI_NODATA: - return "No address associated with hostname"; - case EAI_MEMORY: - return "Memory allocation failure"; - case EAI_FAMILY: - return "Address family not supported"; - default: - return "Unknown error"; +char *gai_strerror(int ecode) { + switch(ecode) { + case EAI_NODATA: + return "No address associated with hostname"; + + case EAI_MEMORY: + return "Memory allocation failure"; + + case EAI_FAMILY: + return "Address family not supported"; + + default: + return "Unknown error"; } -} +} #endif /* !HAVE_GAI_STRERROR */ #if !HAVE_DECL_FREEADDRINFO -void freeaddrinfo(struct addrinfo *ai) -{ +void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next; while(ai) { @@ -46,56 +47,58 @@ void freeaddrinfo(struct addrinfo *ai) #endif /* !HAVE_FREEADDRINFO */ #if !HAVE_DECL_GETADDRINFO -static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) -{ +static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) { struct addrinfo *ai; ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); - + ai->ai_addr = (struct sockaddr *)(ai + 1); ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr->sa_family = ai->ai_family = AF_INET; ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; - + return ai; } -int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) -{ +int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *prev = NULL; struct hostent *hp; struct in_addr in = {0}; int i; uint16_t port = 0; - if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) + if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) { return EAI_FAMILY; + } - if (servname) + if(servname) { port = htons(atoi(servname)); + } - if (hints && hints->ai_flags & AI_PASSIVE) { + if(hints && hints->ai_flags & AI_PASSIVE) { *res = malloc_ai(port, htonl(0x00000000)); return 0; } - - if (!hostname) { + + if(!hostname) { *res = malloc_ai(port, htonl(0x7f000001)); return 0; } - + hp = gethostbyname(hostname); - if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) + if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) { return EAI_NODATA; + } - for (i = 0; hp->h_addr_list[i]; i++) { + for(i = 0; hp->h_addr_list[i]; i++) { *res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr); - if(prev) + if(prev) { prev->ai_next = *res; + } prev = *res; } diff --git a/src/fake-getaddrinfo.h b/src/fake-getaddrinfo.h index 9316f5a..a79a611 100644 --- a/src/fake-getaddrinfo.h +++ b/src/fake-getaddrinfo.h @@ -2,15 +2,15 @@ #define TINC_FAKE_GETADDRINFO_H #ifndef EAI_NODATA -#define EAI_NODATA 1 +#define EAI_NODATA 1 #endif #ifndef EAI_MEMORY -#define EAI_MEMORY 2 +#define EAI_MEMORY 2 #endif #ifndef EAI_FAMILY -#define EAI_FAMILY 3 +#define EAI_FAMILY 3 #endif #ifndef AI_PASSIVE @@ -30,19 +30,19 @@ #ifndef HAVE_STRUCT_ADDRINFO struct addrinfo { - int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - size_t ai_addrlen; /* length of ai_addr */ - char *ai_canonname; /* canonical name for hostname */ - struct sockaddr *ai_addr; /* binary address */ - struct addrinfo *ai_next; /* next structure in linked list */ + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ }; #endif /* !HAVE_STRUCT_ADDRINFO */ #if !HAVE_DECL_GETADDRINFO -int getaddrinfo(const char *hostname, const char *servname, +int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res); #endif /* !HAVE_GETADDRINFO */ diff --git a/src/fake-getnameinfo.c b/src/fake-getnameinfo.c index 8047173..88b78a5 100644 --- a/src/fake-getnameinfo.c +++ b/src/fake-getnameinfo.c @@ -16,39 +16,48 @@ #if !HAVE_DECL_GETNAMEINFO -int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) -{ +int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; struct hostent *hp; int len; - if(sa->sa_family != AF_INET) + if(sa->sa_family != AF_INET) { return EAI_FAMILY; + } if(serv && servlen) { len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); - if(len < 0 || len >= servlen) + + if(len < 0 || len >= servlen) { return EAI_MEMORY; + } } - if(!host || !hostlen) + if(!host || !hostlen) { return 0; + } if(flags & NI_NUMERICHOST) { len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); - if(len < 0 || len >= hostlen) + + if(len < 0 || len >= hostlen) { return EAI_MEMORY; + } + return 0; } hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); - - if(!hp || !hp->h_name || !hp->h_name[0]) + + if(!hp || !hp->h_name || !hp->h_name[0]) { return EAI_NODATA; - + } + len = snprintf(host, hostlen, "%s", hp->h_name); - if(len < 0 || len >= hostlen) + + if(len < 0 || len >= hostlen) { return EAI_MEMORY; + } return 0; } diff --git a/src/fake-getnameinfo.h b/src/fake-getnameinfo.h index f939ffc..4f24ad1 100644 --- a/src/fake-getnameinfo.h +++ b/src/fake-getnameinfo.h @@ -2,7 +2,7 @@ #define TINC_FAKE_GETNAMEINFO_H #if !HAVE_DECL_GETNAMEINFO -int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, +int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); #endif /* !HAVE_GETNAMEINFO */ diff --git a/src/getopt.c b/src/getopt.c index 273a000..f84562c 100644 --- a/src/getopt.c +++ b/src/getopt.c @@ -4,7 +4,7 @@ before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 - Free Software Foundation, Inc. + Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. @@ -69,12 +69,12 @@ with this program; if not, write to the Free Software Foundation, Inc., /* This needs to come after some library #include to get GNU_LIBRARY defined. */ -#ifdef GNU_LIBRARY +#ifdef GNU_LIBRARY /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #include -#endif /* GNU C library. */ +#endif /* GNU C library. */ #ifdef VMS #include @@ -183,40 +183,41 @@ int optopt = '?'; of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +static enum { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; -#ifdef GNU_LIBRARY +#ifdef GNU_LIBRARY /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include -#define my_index strchr +#define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ -char *getenv (); +char *getenv(); static char * -my_index (str, chr) - const char *str; - int chr; +my_index(str, chr) +const char *str; +int chr; { - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; + while(*str) { + if(*str == chr) { + return (char *) str; + } + + str++; + } + + return 0; } /* If using GCC, we can safely declare strlen this way. @@ -227,7 +228,7 @@ my_index (str, chr) #if !defined (STDC) || !STDC /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); +extern int strlen(const char *); #endif /* not STDC */ #endif /* GNUC */ @@ -261,26 +262,25 @@ extern pid_t libc_pid; is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void -__attribute__ ((__unused__)) -store_args_and_env (int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; +__attribute__((__unused__)) +store_args_and_env(int argc, char *const *argv) { + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; } -text_set_element (libc_subinit, store_args_and_env); +text_set_element(libc_subinit, store_args_and_env); # define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char tmp = getopt_nonoption_flags[ch1]; \ - getopt_nonoption_flags[ch1] = getopt_nonoption_flags[ch2]; \ - getopt_nonoption_flags[ch2] = tmp; \ - } -#else /* !_LIBC */ + if (nonoption_flags_len > 0) \ + { \ + char tmp = getopt_nonoption_flags[ch1]; \ + getopt_nonoption_flags[ch1] = getopt_nonoption_flags[ch2]; \ + getopt_nonoption_flags[ch2] = tmp; \ + } +#else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ +#endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) @@ -292,161 +292,158 @@ text_set_element (libc_subinit, store_args_and_env); the new indices of the non-options in ARGV after they are moved. */ #if defined (STDC) && STDC -static void exchange (char **); +static void exchange(char **); #endif static void -exchange (argv) - char **argv; +exchange(argv) +char **argv; { - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ #ifdef _LIBC - /* First make sure the handling of the `getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memcpy (new_str, getopt_nonoption_flags, nonoption_flags_max_len); - memset (&new_str[nonoption_flags_max_len], '\0', - top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - getopt_nonoption_flags = new_str; + + /* First make sure the handling of the `getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if(nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc(top + 1); + + if(new_str == NULL) { + nonoption_flags_len = nonoption_flags_max_len = 0; + } else { + memcpy(new_str, getopt_nonoption_flags, nonoption_flags_max_len); + memset(&new_str[nonoption_flags_max_len], '\0', + top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + getopt_nonoption_flags = new_str; + } } - } + #endif - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; + while(top > middle && middle > bottom) { + if(top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for(i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); + } + + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for(i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } } - } - /* Update records for the slots the non-options now occupy. */ + /* Update records for the slots the non-options now occupy. */ - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined (STDC) && STDC -static const char *_getopt_initialize (int, char *const *, const char *); +static const char *_getopt_initialize(int, char *const *, const char *); #endif static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +_getopt_initialize(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; { - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ - first_nonopt = last_nonopt = optind; + first_nonopt = last_nonopt = optind; - nextchar = NULL; + nextchar = NULL; - posixly_correct = getenv ("POSIXLY_CORRECT"); + posixly_correct = getenv("POSIXLY_CORRECT"); - /* Determine how to handle the ordering of options and nonoptions. */ + /* Determine how to handle the ordering of options and nonoptions. */ - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; + if(optstring[0] == '-') { + ordering = RETURN_IN_ORDER; + ++optstring; + } else if(optstring[0] == '+') { + ordering = REQUIRE_ORDER; + ++optstring; + } else if(posixly_correct != NULL) { + ordering = REQUIRE_ORDER; + } else { + ordering = PERMUTE; + } #ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) - { - if (nonoption_flags_max_len == 0) - { - if (getopt_nonoption_flags == NULL - || getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - { - memcpy (getopt_nonoption_flags, orig_str, len); - memset (&getopt_nonoption_flags[len], '\0', - nonoption_flags_max_len - len); + + if(posixly_correct == NULL + && argc == original_argc && argv == original_argv) { + if(nonoption_flags_max_len == 0) { + if(getopt_nonoption_flags == NULL + || getopt_nonoption_flags[0] == '\0') { + nonoption_flags_max_len = -1; + } else { + const char *orig_str = getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen(orig_str); + + if(nonoption_flags_max_len < argc) { + nonoption_flags_max_len = argc; + } + + getopt_nonoption_flags = + (char *) malloc(nonoption_flags_max_len); + + if(getopt_nonoption_flags == NULL) { + nonoption_flags_max_len = -1; + } else { + memcpy(getopt_nonoption_flags, orig_str, len); + memset(&getopt_nonoption_flags[len], '\0', + nonoption_flags_max_len - len); + } + } } - } + + nonoption_flags_len = nonoption_flags_max_len; + } else { + nonoption_flags_len = 0; } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; + #endif - return optstring; + return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters @@ -506,474 +503,476 @@ _getopt_initialize (argc, argv, optstring) long-named options. */ int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; +_getopt_internal(argc, argv, optstring, longopts, longind, long_only) +int argc; +char *const *argv; +const char *optstring; +const struct option *longopts; +int *longind; +int long_only; { - optarg = NULL; - - if (optind == 0 || !getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ + optarg = NULL; + + if(optind == 0 || !getopt_initialized) { + if(optind == 0) { + optind = 1; /* Don't scan ARGV[0], the program name. */ + } + + optstring = _getopt_initialize(argc, argv, optstring); + getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ #ifdef _LIBC -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && getopt_nonoption_flags[optind] == '1')) +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && getopt_nonoption_flags[optind] == '1')) #else #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ + if(nextchar == NULL || *nextchar == '\0') { + /* Advance to the next ARGV-element. */ - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if(last_nonopt > optind) { + last_nonopt = optind; + } - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ + if(first_nonopt > optind) { + first_nonopt = optind; + } - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; + if(ordering == PERMUTE) { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ + if(first_nonopt != last_nonopt && last_nonopt != optind) { + exchange((char **) argv); + } else if(last_nonopt != optind) { + first_nonopt = optind; + } - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ + while(optind < argc && NONOPTION_P) { + optind++; + } - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; + last_nonopt = optind; + } - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ - optind = argc; - } + if(optind != argc && !strcmp(argv[optind], "--")) { + optind++; - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ + if(first_nonopt != last_nonopt && last_nonopt != optind) { + exchange((char **) argv); + } else if(first_nonopt == last_nonopt) { + first_nonopt = optind; + } - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } + last_nonopt = argc; - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ + optind = argc; + } - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; + if(optind == argc) { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if(first_nonopt != last_nonopt) { + optind = first_nonopt; + } + + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if(NONOPTION_P) { + if(ordering == REQUIRE_ORDER) { + return -1; + } + + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); } - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if(longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for(nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for(p = longopts, option_index = 0; p->name; p++, option_index++) + if(!strncmp(p->name, nextchar, nameend - nextchar)) { + if((unsigned int)(nameend - nextchar) + == (unsigned int) strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if(pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else + /* Second or later nonexact match found. */ + { + ambig = 1; + } + } + + if(ambig && !exact) { + if(opterr) + fprintf(stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; + + if(pfound != NULL) { + option_index = indfound; + optind++; + + if(*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if(pfound->has_arg) { + optarg = nameend + 1; + } else { + if(opterr) { + if(argv[optind - 1][1] == '-') + /* --option */ + fprintf(stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf(stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen(nextchar); + + optopt = pfound->val; + return '?'; + } + } else if(pfound->has_arg == 1) { + if(optind < argc) { + optarg = argv[optind++]; + } else { + if(opterr) + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + + nextchar += strlen(nextchar); + + if(longind != NULL) { + *longind = option_index; + } + + if(pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if(!long_only || argv[optind][1] == '-' + || my_index(optstring, *nextchar) == NULL) { + if(opterr) { + if(argv[optind][1] == '-') + /* --option */ + fprintf(stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf(stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; } - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) + /* Look at and handle the next short option-character. */ + { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", - argv[0], c); - else - fprintf (stderr, "%s: invalid option -- %c\n", - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; + char c = *nextchar++; + char *temp = my_index(optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if(*nextchar == '\0') { + ++optind; } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; + + if(temp == NULL || c == ':') { + if(opterr) { + if(posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, "%s: illegal option -- %c\n", + argv[0], c); + else + fprintf(stderr, "%s: invalid option -- %c\n", + argv[0], c); + } + + optopt = c; + return '?'; + } + + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if(temp[0] == 'W' && temp[1] == ';') { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if(*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if(optind == argc) { + if(opterr) { + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + + optopt = c; + + if(optstring[0] == ':') { + c = ':'; + } else { + c = '?'; + } + + return c; + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + { + optarg = argv[optind++]; + } + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for(nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for(p = longopts, option_index = 0; p->name; p++, option_index++) + if(!strncmp(p->name, nextchar, nameend - nextchar)) { + if((unsigned int)(nameend - nextchar) == strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if(pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else + /* Second or later nonexact match found. */ + { + ambig = 1; + } + } + + if(ambig && !exact) { + if(opterr) + fprintf(stderr, "%s: option `-W %s' is ambiguous\n", + argv[0], argv[optind]); + + nextchar += strlen(nextchar); + optind++; + return '?'; + } + + if(pfound != NULL) { + option_index = indfound; + + if(*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if(pfound->has_arg) { + optarg = nameend + 1; + } else { + if(opterr) + fprintf(stderr, + "%s: option `-W %s' doesn't allow an argument\n", + argv[0], pfound->name); + + nextchar += strlen(nextchar); + return '?'; + } + } else if(pfound->has_arg == 1) { + if(optind < argc) { + optarg = argv[optind++]; + } else { + if(opterr) + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + + nextchar += strlen(nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + + nextchar += strlen(nextchar); + + if(longind != NULL) { + *longind = option_index; + } + + if(pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + + return pfound->val; + } + + nextchar = NULL; + return 'W'; /* Let the application handle it. */ } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `-W %s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - fprintf (stderr, - "%s: option `-W %s' doesn't allow an argument\n", - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - "%s: option requires an argument -- %c\n", - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } + + if(temp[1] == ':') { + if(temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if(*nextchar != '\0') { + optarg = nextchar; + optind++; + } else { + optarg = NULL; + } + + nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if(*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if(optind == argc) { + if(opterr) { + /* 1003.2 specifies the format of this message. */ + fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], c); + } + + optopt = c; + + if(optstring[0] == ':') { + c = ':'; + } else { + c = '?'; + } + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + { + optarg = argv[optind++]; + } + + nextchar = NULL; + } + } + + return c; + } } int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +getopt(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; { - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); + return _getopt_internal(argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); } -#endif /* Not ELIDE_CODE. */ +#endif /* Not ELIDE_CODE. */ #ifdef TEST @@ -981,68 +980,72 @@ getopt (argc, argv, optstring) the above definition of `getopt'. */ int -main (argc, argv) - int argc; - char **argv; +main(argc, argv) +int argc; +char **argv; { - int c; - int digit_optind = 0; + int c; + int digit_optind = 0; - while (1) - { - int this_option_optind = optind ? optind : 1; + while(1) { + int this_option_optind = optind ? optind : 1; - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; + c = getopt(argc, argv, "abc:d:0123456789"); - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); + if(c == -1) { + break; + } + + switch(c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(digit_optind != 0 && digit_optind != this_option_optind) { + printf("digits occur in two different argv-elements.\n"); + } + + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } } - } - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } + if(optind < argc) { + printf("non-option ARGV-elements: "); + + while(optind < argc) { + printf("%s ", argv[optind++]); + } + + printf("\n"); + } - exit (0); + exit(0); } #endif /* TEST */ diff --git a/src/getopt.h b/src/getopt.h index 2290d7c..cd77d67 100644 --- a/src/getopt.h +++ b/src/getopt.h @@ -22,111 +22,110 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef cplusplus +#ifdef cplusplus extern "C" { #endif -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ + /* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ -extern char *optarg; + extern char *optarg; -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. + /* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. - On entry to `getopt', zero means this is the first call; initialize. + On entry to `getopt', zero means this is the first call; initialize. - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ -extern int optind; + extern int optind; -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ + /* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ -extern int opterr; + extern int opterr; -/* Set to an option character which was unrecognized. */ + /* Set to an option character which was unrecognized. */ -extern int optopt; + extern int optopt; -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. + /* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ -struct option -{ + struct option { #if defined (STDC) && STDC - const char *name; + const char *name; #else - char *name; + char *name; #endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; + }; -/* Names for the values of the `has_arg' field of `struct option'. */ + /* Names for the values of the `has_arg' field of `struct option'. */ -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 #if defined (STDC) && STDC #ifdef GNU_LIBRARY -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); + /* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ + extern int getopt(int argc, char *const *argv, const char *shortopts); #else /* not GNU_LIBRARY */ -extern int getopt (); + extern int getopt(); #endif /* GNU_LIBRARY */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); + extern int getopt_long(int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); + extern int getopt_long_only(int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + + /* Internal only. Users should not call this directly. */ + extern int _getopt_internal(int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); #else /* not STDC */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); + extern int getopt(); + extern int getopt_long(); + extern int getopt_long_only(); -extern int _getopt_internal (); + extern int _getopt_internal(); #endif /* STDC */ -#ifdef cplusplus +#ifdef cplusplus } #endif diff --git a/src/getopt1.c b/src/getopt1.c index 07f5b2d..87ee95e 100644 --- a/src/getopt1.c +++ b/src/getopt1.c @@ -60,19 +60,19 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #endif -#ifndef NULL +#ifndef NULL #define NULL 0 #endif int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +getopt_long(argc, argv, options, long_options, opt_index) +int argc; +char *const *argv; +const char *options; +const struct option *long_options; +int *opt_index; { - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); + return _getopt_internal(argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. @@ -81,109 +81,115 @@ getopt_long (argc, argv, options, long_options, opt_index) instead. */ int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +getopt_long_only(argc, argv, options, long_options, opt_index) +int argc; +char *const *argv; +const char *options; +const struct option *long_options; +int *opt_index; { - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); + return _getopt_internal(argc, argv, options, long_options, opt_index, 1); } -#endif /* Not ELIDE_CODE. */ +#endif /* Not ELIDE_CODE. */ #ifdef TEST #include int -main (argc, argv) - int argc; - char **argv; +main(argc, argv) +int argc; +char **argv; { - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); + int c; + int digit_optind = 0; + + while(1) { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "abc:d:0123456789", + long_options, &option_index); + + if(c == -1) { + break; + } + + switch(c) { + case 0: + printf("option %s", long_options[option_index].name); + + if(optarg) { + printf(" with arg %s", optarg); + } + + printf("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(digit_optind != 0 && digit_optind != this_option_optind) { + printf("digits occur in two different argv-elements.\n"); + } + + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case 'd': + printf("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } } - } - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } + if(optind < argc) { + printf("non-option ARGV-elements: "); - exit (0); + while(optind < argc) { + printf("%s ", argv[optind++]); + } + + printf("\n"); + } + + exit(0); } #endif /* TEST */ diff --git a/src/graph.c b/src/graph.c index 5b90c62..832e017 100644 --- a/src/graph.c +++ b/src/graph.c @@ -84,8 +84,9 @@ static void mst_kruskal(void) { /* Do we have something to do at all? */ - if(!edge_weight_tree->head) + if(!edge_weight_tree->head) { return; + } ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:"); @@ -101,6 +102,7 @@ static void mst_kruskal(void) { for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; + if(e->from->status.reachable) { e->from->status.visited = true; break; @@ -121,16 +123,18 @@ static void mst_kruskal(void) { e->from->status.visited = true; e->to->status.visited = true; - if(e->connection) + if(e->connection) { e->connection->status.mst = true; + } - if(e->reverse->connection) + if(e->reverse->connection) { e->reverse->connection->status.mst = true; + } safe_edges++; ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name, - e->to->name, e->weight); + e->to->name, e->weight); if(skipped) { skipped = false; @@ -140,7 +144,7 @@ static void mst_kruskal(void) { } ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes, - safe_edges); + safe_edges); } /* Implementation of a simple breadth-first search algorithm. @@ -180,22 +184,23 @@ static void sssp_bfs(void) { /* Loop while todo_list is filled */ - for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */ + for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */ n = from->data; - for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ + for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ e = to->data; - if(!e->reverse) + if(!e->reverse) { continue; + } /* Situation: - / - / + / + / ----->(n)---e-->(e->to) - \ - \ + \ + \ Where e is an edge, (n) and (e->to) are nodes. n->address is set to the e->address of the edge left of n to n. @@ -209,13 +214,15 @@ static void sssp_bfs(void) { indirect = n->status.indirect || e->options & OPTION_INDIRECT; if(e->to->status.visited - && (!e->to->status.indirect || indirect)) + && (!e->to->status.indirect || indirect)) { continue; + } // Only update nexthop the first time we visit this node. - if(!e->to->status.visited) + if(!e->to->status.visited) { e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; + } e->to->status.visited = true; e->to->status.indirect = indirect; @@ -223,8 +230,9 @@ static void sssp_bfs(void) { e->to->via = indirect ? n->via : e->to; e->to->options = e->options; - if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) + if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) { update_node_udp(e->to, &e->address); + } list_insert_tail(todo_list, e->to); } @@ -246,10 +254,10 @@ static void sssp_bfs(void) { if(n->status.reachable) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable", - n->name, n->hostname); + n->name, n->hostname); } else { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable", - n->name, n->hostname); + n->name, n->hostname); } /* TODO: only clear status.validkey if node is unreachable? */ @@ -278,16 +286,17 @@ static void sssp_bfs(void) { execute_script(n->status.reachable ? "host-up" : "host-down", envp); xasprintf(&name, - n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", - n->name); + n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", + n->name); execute_script(name, envp); free(name); free(address); free(port); - for(i = 0; i < 7; i++) + for(i = 0; i < 7; i++) { free(envp[i]); + } subnet_update(n, NULL, n->status.reachable); @@ -312,7 +321,7 @@ void graph(void) { /* Dump nodes and edges to a graphviz file. - + The file can be converted to an image with dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true */ @@ -323,14 +332,15 @@ void dump_graph(void) { edge_t *e; char *filename = NULL, *tmpname = NULL; FILE *file, *pipe = NULL; - - if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) + + if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) { return; + } graph_changed = false; ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph"); - + if(filename[0] == '|') { file = pipe = popen(filename + 1, "w"); } else { @@ -346,7 +356,7 @@ void dump_graph(void) { } fprintf(file, "digraph {\n"); - + /* dump all nodes first */ for(node = node_tree->head; node; node = node->next) { n = node->data; @@ -359,8 +369,8 @@ void dump_graph(void) { fprintf(file, " %s -> %s;\n", e->from->name, e->to->name); } - fprintf(file, "}\n"); - + fprintf(file, "}\n"); + if(pipe) { pclose(pipe); } else { @@ -368,8 +378,11 @@ void dump_graph(void) { #ifdef HAVE_MINGW unlink(filename); #endif - if(rename(tmpname, filename)) + + if(rename(tmpname, filename)) { logger(LOG_ERR, "Could not rename %s to %s: %s\n", tmpname, filename, strerror(errno)); + } + free(tmpname); } diff --git a/src/ipv4.h b/src/ipv4.h index 5fc1afe..7f45ad7 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -64,15 +64,15 @@ #ifndef HAVE_STRUCT_IP struct ip { #if BYTE_ORDER == LITTLE_ENDIAN - unsigned int ip_hl:4; - unsigned int ip_v:4; + unsigned int ip_hl: 4; + unsigned int ip_v: 4; #else - unsigned int ip_v:4; - unsigned int ip_hl:4; + unsigned int ip_v: 4; + unsigned int ip_hl: 4; #endif uint8_t ip_tos; uint16_t ip_len; - uint16_t ip_id; + uint16_t ip_id; uint16_t ip_off; #define IP_RF 0x8000 #define IP_DF 0x4000 @@ -81,7 +81,7 @@ struct ip { uint8_t ip_p; uint16_t ip_sum; struct in_addr ip_src, ip_dst; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #endif #ifndef IP_OFFMASK @@ -143,7 +143,7 @@ struct icmp { #define icmp_radv icmp_dun.id_radv #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #endif #endif diff --git a/src/ipv6.h b/src/ipv6.h index b6862b6..1642278 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -36,7 +36,7 @@ struct in6_addr { uint16_t u6_addr16[8]; uint32_t u6_addr32[4]; } in6_u; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 @@ -49,14 +49,14 @@ struct sockaddr_in6 { uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #endif #ifndef IN6_IS_ADDR_V4MAPPED #define IN6_IS_ADDR_V4MAPPED(a) \ - ((((const uint32_t *) (a))[0] == 0) \ - && (((const uint32_t *) (a))[1] == 0) \ - && (((const uint32_t *) (a))[2] == htonl (0xffff))) + ((((const uint32_t *) (a))[0] == 0) \ + && (((const uint32_t *) (a))[1] == 0) \ + && (((const uint32_t *) (a))[2] == htonl (0xffff))) #endif #ifndef HAVE_STRUCT_IP6_HDR @@ -72,7 +72,7 @@ struct ip6_hdr { } ip6_ctlun; struct in6_addr ip6_src; struct in6_addr ip6_dst; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen @@ -91,7 +91,7 @@ struct icmp6_hdr { uint16_t icmp6_un_data16[2]; uint8_t icmp6_un_data8[4]; } icmp6_dataun; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #define ICMP6_DST_UNREACH_NOROUTE 0 #define ICMP6_DST_UNREACH 1 #define ICMP6_PACKET_TOO_BIG 2 @@ -111,7 +111,7 @@ struct icmp6_hdr { struct nd_neighbor_solicit { struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_TARGET_LINKADDR 2 #define nd_ns_type nd_ns_hdr.icmp6_type @@ -124,7 +124,7 @@ struct nd_neighbor_solicit { struct nd_opt_hdr { uint8_t nd_opt_type; uint8_t nd_opt_len; -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); #endif #endif diff --git a/src/linux/device.c b/src/linux/device.c index 8d042d2..f75f4bd 100644 --- a/src/linux/device.c +++ b/src/linux/device.c @@ -56,13 +56,16 @@ static bool setup_device(void) { struct ifreq ifr; bool t1q = false; - if(!get_config_string(lookup_config(config_tree, "Device"), &device)) + if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { device = xstrdup(DEFAULT_DEVICE); + } if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) #ifdef HAVE_LINUX_IF_TUN_H - if (netname != NULL) + if(netname != NULL) { iface = xstrdup(netname); + } + #else iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); #endif @@ -94,17 +97,22 @@ static bool setup_device(void) { device_type = DEVICE_TYPE_TUN; device_info = "Linux tun/tap device (tun mode)"; } else { - if (routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { overwrite_mac = true; + } + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; device_type = DEVICE_TYPE_TAP; device_info = "Linux tun/tap device (tap mode)"; } #ifdef IFF_ONE_QUEUE + /* Set IFF_ONE_QUEUE flag... */ - if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) + if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) { ifr.ifr_flags |= IFF_ONE_QUEUE; + } + #endif if(iface) { @@ -126,16 +134,19 @@ static bool setup_device(void) { } else #endif { - if(routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { overwrite_mac = true; + } + device_info = "Linux ethertap device"; device_type = DEVICE_TYPE_ETHERTAP; free(iface); iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); } - if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) + if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) { memcpy(mymac.x, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + } logger(LOG_INFO, "%s is a %s", device, device_info); @@ -152,81 +163,89 @@ static void close_device(void) { static bool read_packet(vpn_packet_t *packet) { int lenin; - + switch(device_type) { - case DEVICE_TYPE_TUN: - lenin = read(device_fd, packet->data + 10, MTU - 10); - - if(lenin <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", - device_info, device, strerror(errno)); - return false; - } - - memset(packet->data, 0, 12); - packet->len = lenin + 10; - break; - case DEVICE_TYPE_TAP: - lenin = read(device_fd, packet->data, MTU); - - if(lenin <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", - device_info, device, strerror(errno)); - return false; - } - - packet->len = lenin; - break; - case DEVICE_TYPE_ETHERTAP: - lenin = read(device_fd, packet->data - 2, MTU + 2); - - if(lenin <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", - device_info, device, strerror(errno)); - return false; - } - - packet->len = lenin - 2; - break; + case DEVICE_TYPE_TUN: + lenin = read(device_fd, packet->data + 10, MTU - 10); + + if(lenin <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", + device_info, device, strerror(errno)); + return false; + } + + memset(packet->data, 0, 12); + packet->len = lenin + 10; + break; + + case DEVICE_TYPE_TAP: + lenin = read(device_fd, packet->data, MTU); + + if(lenin <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", + device_info, device, strerror(errno)); + return false; + } + + packet->len = lenin; + break; + + case DEVICE_TYPE_ETHERTAP: + lenin = read(device_fd, packet->data - 2, MTU + 2); + + if(lenin <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", + device_info, device, strerror(errno)); + return false; + } + + packet->len = lenin - 2; + break; } device_total_in += packet->len; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, - device_info); + device_info); return true; } static bool write_packet(vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); switch(device_type) { - case DEVICE_TYPE_TUN: - packet->data[10] = packet->data[11] = 0; - if(write(device_fd, packet->data + 10, packet->len - 10) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); - return false; - } - break; - case DEVICE_TYPE_TAP: - if(write(device_fd, packet->data, packet->len) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); - return false; - } - break; - case DEVICE_TYPE_ETHERTAP: - memcpy(packet->data - 2, &packet->len, 2); - - if(write(device_fd, packet->data - 2, packet->len + 2) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); - return false; - } - break; + case DEVICE_TYPE_TUN: + packet->data[10] = packet->data[11] = 0; + + if(write(device_fd, packet->data + 10, packet->len - 10) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, + strerror(errno)); + return false; + } + + break; + + case DEVICE_TYPE_TAP: + if(write(device_fd, packet->data, packet->len) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, + strerror(errno)); + return false; + } + + break; + + case DEVICE_TYPE_ETHERTAP: + memcpy(packet->data - 2, &packet->len, 2); + + if(write(device_fd, packet->data - 2, packet->len + 2) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, + strerror(errno)); + return false; + } + + break; } device_total_out += packet->len; diff --git a/src/list.c b/src/list.c index a26c58d..a807c6d 100644 --- a/src/list.c +++ b/src/list.c @@ -43,8 +43,9 @@ list_node_t *list_alloc_node(void) { } void list_free_node(list_t *list, list_node_t *node) { - if(node->data && list->delete) + if(node->data && list->delete) { list->delete(node->data); + } free(node); } @@ -61,10 +62,11 @@ list_node_t *list_insert_head(list_t *list, void *data) { node->next = list->head; list->head = node; - if(node->next) + if(node->next) { node->next->prev = node; - else + } else { list->tail = node; + } list->count++; @@ -81,10 +83,11 @@ list_node_t *list_insert_tail(list_t *list, void *data) { node->prev = list->tail; list->tail = node; - if(node->prev) + if(node->prev) { node->prev->next = node; - else + } else { list->head = node; + } list->count++; @@ -92,15 +95,17 @@ list_node_t *list_insert_tail(list_t *list, void *data) { } void list_unlink_node(list_t *list, list_node_t *node) { - if(node->prev) + if(node->prev) { node->prev->next = node->next; - else + } else { list->head = node->next; + } - if(node->next) + if(node->next) { node->next->prev = node->prev; - else + } else { list->tail = node->prev; + } list->count--; } @@ -121,17 +126,19 @@ void list_delete_tail(list_t *list) { /* Head/tail lookup */ void *list_get_head(list_t *list) { - if(list->head) + if(list->head) { return list->head->data; - else + } else { return NULL; + } } void *list_get_tail(list_t *list) { - if(list->tail) + if(list->tail) { return list->tail->data; - else + } else { return NULL; + } } /* Fast list deletion */ @@ -163,7 +170,9 @@ void list_foreach(list_t *list, list_action_t action) { for(node = list->head; node; node = next) { next = node->next; - if(node->data) + + if(node->data) { action(node->data); + } } } diff --git a/src/list.h b/src/list.h index 2b22c04..69d1ff4 100644 --- a/src/list.h +++ b/src/list.h @@ -45,7 +45,7 @@ typedef struct list_t { /* (De)constructors */ -extern list_t *list_alloc(list_action_t) __attribute__ ((__malloc__)); +extern list_t *list_alloc(list_action_t) __attribute__((__malloc__)); extern void list_free(list_t *); extern list_node_t *list_alloc_node(void); extern void list_free_node(list_t *, list_node_t *); diff --git a/src/logger.c b/src/logger.c index 77c8133..89dbe26 100644 --- a/src/logger.c +++ b/src/logger.c @@ -36,48 +36,58 @@ static const char *logident = NULL; void openlogger(const char *ident, logmode_t mode) { logident = ident; logmode = mode; - + switch(mode) { - case LOGMODE_STDERR: - logpid = getpid(); - break; - case LOGMODE_FILE: - logpid = getpid(); - logfile = fopen(logfilename, "a"); - if(!logfile) { - fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno)); - logmode = LOGMODE_NULL; - } - break; - case LOGMODE_SYSLOG: + case LOGMODE_STDERR: + logpid = getpid(); + break; + + case LOGMODE_FILE: + logpid = getpid(); + logfile = fopen(logfilename, "a"); + + if(!logfile) { + fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno)); + logmode = LOGMODE_NULL; + } + + break; + + case LOGMODE_SYSLOG: #ifdef HAVE_MINGW - loghandle = RegisterEventSource(NULL, logident); - if(!loghandle) { - fprintf(stderr, "Could not open log handle!"); - logmode = LOGMODE_NULL; - } - break; + loghandle = RegisterEventSource(NULL, logident); + + if(!loghandle) { + fprintf(stderr, "Could not open log handle!"); + logmode = LOGMODE_NULL; + } + + break; #else #ifdef HAVE_SYSLOG_H - openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON); - break; + openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON); + break; #endif #endif - case LOGMODE_NULL: - break; + + case LOGMODE_NULL: + break; } } void reopenlogger() { - if(logmode != LOGMODE_FILE) + if(logmode != LOGMODE_FILE) { return; + } fflush(logfile); FILE *newfile = fopen(logfilename, "a"); + if(!newfile) { logger(LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno)); return; } + fclose(logfile); logfile = newfile; } @@ -90,44 +100,48 @@ void logger(int priority, const char *format, ...) { va_start(ap, format); switch(logmode) { - case LOGMODE_STDERR: - vfprintf(stderr, format, ap); - fprintf(stderr, "\n"); - fflush(stderr); - break; - case LOGMODE_FILE: - now = time(NULL); - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now)); - fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid); - vfprintf(logfile, format, ap); - fprintf(logfile, "\n"); - fflush(logfile); - break; - case LOGMODE_SYSLOG: + case LOGMODE_STDERR: + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + fflush(stderr); + break; + + case LOGMODE_FILE: + now = time(NULL); + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now)); + fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid); + vfprintf(logfile, format, ap); + fprintf(logfile, "\n"); + fflush(logfile); + break; + + case LOGMODE_SYSLOG: #ifdef HAVE_MINGW - { - char message[4096]; - const char *messages[] = {message}; - vsnprintf(message, sizeof(message), format, ap); - message[sizeof(message) - 1] = 0; - ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL); - } + { + char message[4096]; + const char *messages[] = {message}; + vsnprintf(message, sizeof(message), format, ap); + message[sizeof(message) - 1] = 0; + ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL); + } + #else #ifdef HAVE_SYSLOG_H #ifdef HAVE_VSYSLOG - vsyslog(priority, format, ap); + vsyslog(priority, format, ap); #else - { - char message[4096]; - vsnprintf(message, sizeof(message), format, ap); - syslog(priority, "%s", message); - } + { + char message[4096]; + vsnprintf(message, sizeof(message), format, ap); + syslog(priority, "%s", message); + } #endif - break; + break; #endif #endif - case LOGMODE_NULL: - break; + + case LOGMODE_NULL: + break; } va_end(ap); @@ -135,22 +149,24 @@ void logger(int priority, const char *format, ...) { void closelogger(void) { switch(logmode) { - case LOGMODE_FILE: - fclose(logfile); - break; - case LOGMODE_SYSLOG: + case LOGMODE_FILE: + fclose(logfile); + break; + + case LOGMODE_SYSLOG: #ifdef HAVE_MINGW - DeregisterEventSource(loghandle); - break; + DeregisterEventSource(loghandle); + break; #else #ifdef HAVE_SYSLOG_H - closelog(); - break; + closelog(); + break; #endif #endif - case LOGMODE_NULL: - case LOGMODE_STDERR: - break; - break; + + case LOGMODE_NULL: + case LOGMODE_STDERR: + break; + break; } } diff --git a/src/logger.h b/src/logger.h index f50c17e..1c5d80e 100644 --- a/src/logger.h +++ b/src/logger.h @@ -21,16 +21,16 @@ */ typedef enum debug_t { - DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */ + DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */ DEBUG_ALWAYS = 0, - DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */ - DEBUG_ERROR = 2, /* Show error messages received from other hosts */ - DEBUG_STATUS = 2, /* Show status messages received from other hosts */ - DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */ - DEBUG_META = 4, /* Show contents of every request that is sent/received */ - DEBUG_TRAFFIC = 5, /* Show network traffic information */ - DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */ - DEBUG_SCARY_THINGS = 10 /* You have been warned */ + DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */ + DEBUG_ERROR = 2, /* Show error messages received from other hosts */ + DEBUG_STATUS = 2, /* Show status messages received from other hosts */ + DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */ + DEBUG_META = 4, /* Show contents of every request that is sent/received */ + DEBUG_TRAFFIC = 5, /* Show network traffic information */ + DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */ + DEBUG_SCARY_THINGS = 10 /* You have been warned */ } debug_t; typedef enum logmode_t { @@ -67,7 +67,7 @@ enum { extern debug_t debug_level; extern void openlogger(const char *, logmode_t); extern void reopenlogger(void); -extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3))); +extern void logger(int, const char *, ...) __attribute__((__format__(printf, 2, 3))); extern void closelogger(void); #define ifdebug(l) if(debug_level >= DEBUG_##l) diff --git a/src/meta.c b/src/meta.c index 60814c7..4930818 100644 --- a/src/meta.c +++ b/src/meta.c @@ -39,10 +39,11 @@ bool send_meta(connection_t *c, const char *buffer, int length) { int result; ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length, - c->name, c->hostname); + c->name, c->hostname); - if(!c->outbuflen) + if(!c->outbuflen) { c->last_flushed_time = now; + } /* Find room in connection's buffer */ if(length + c->outbuflen > c->outbufsize) { @@ -66,15 +67,17 @@ bool send_meta(connection_t *c, const char *buffer, int length) { } result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen, - &outlen, (unsigned char *)buffer, length); + &outlen, (unsigned char *)buffer, length); + if(!result || outlen < length) { logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } else if(outlen > length) { logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!"); abort(); } + c->outbuflen += outlen; } else { memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length); @@ -86,25 +89,26 @@ bool send_meta(connection_t *c, const char *buffer, int length) { bool flush_meta(connection_t *c) { int result; - + ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)", - c->outbuflen, c->name, c->hostname); + c->outbuflen, c->name, c->hostname); while(c->outbuflen) { result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0); + if(result <= 0) { if(!errno || errno == EPIPE) { ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", - c->name, c->hostname); + c->name, c->hostname); } else if(errno == EINTR) { continue; } else if(sockwouldblock(sockerrno)) { ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block", - c->outbuflen, c->name, c->hostname); + c->outbuflen, c->name, c->hostname); return true; } else { logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name, - c->hostname, sockstrerror(sockerrno)); + c->hostname, sockstrerror(sockerrno)); } return false; @@ -125,8 +129,9 @@ void broadcast_meta(connection_t *from, const char *buffer, int length) { for(node = connection_tree->head; node; node = node->next) { c = node->data; - if(c != from && c->status.active) + if(c != from && c->status.active) { send_meta(c, buffer, length); + } } } @@ -150,12 +155,12 @@ bool receive_meta(connection_t *c) { if(lenin <= 0) { if(!lenin || !errno) { ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", - c->name, c->hostname); - } else if(sockwouldblock(sockerrno)) + c->name, c->hostname); + } else if(sockwouldblock(sockerrno)) { return true; - else + } else logger(LOG_ERR, "Metadata socket read error for %s (%s): %s", - c->name, c->hostname, sockstrerror(sockerrno)); + c->name, c->hostname, sockstrerror(sockerrno)); return false; } @@ -170,8 +175,11 @@ bool receive_meta(connection_t *c) { if(c->allow_request == PROXY) { reqlen = receive_proxy_meta(c, oldlen, lenin); - if(reqlen < 0) + + if(reqlen < 0) { return false; + } + goto consume; } @@ -187,11 +195,13 @@ bool receive_meta(connection_t *c) { } result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin); + if(!result || lenout != lenin) { logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } + memcpy(c->buffer + oldlen, inbuf, lenin); decrypted = true; } @@ -214,17 +224,19 @@ bool receive_meta(connection_t *c) { for(i = oldlen; i < c->buflen; i++) { if(c->buffer[i] == '\n') { - c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ + c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ c->reqlen = reqlen = i + 1; break; } } - if(reqlen && !receive_request(c)) + if(reqlen && !receive_request(c)) { return false; + } } consume: + if(reqlen) { c->buflen -= reqlen; lenin -= reqlen - oldlen; @@ -238,7 +250,7 @@ consume: if(c->buflen >= MAXBUFSIZE) { logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)", - c->name, c->hostname); + c->name, c->hostname); return false; } diff --git a/src/mingw/common.h b/src/mingw/common.h index 6e5e75c..41b9dc5 100644 --- a/src/mingw/common.h +++ b/src/mingw/common.h @@ -37,7 +37,7 @@ //============= #define TAP_CONTROL_CODE(request,method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) diff --git a/src/mingw/device.c b/src/mingw/device.c index 3ff6759..341d7a9 100644 --- a/src/mingw/device.c +++ b/src/mingw/device.c @@ -66,17 +66,21 @@ static DWORD WINAPI tapreader(void *bla) { if(!status) { if(GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(r_overlapped.hEvent, INFINITE); - if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE)) + + if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE)) { continue; + } } else { logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); + device, strerror(errno)); errors++; + if(errors >= 10) { EnterCriticalSection(&mutex); running = false; LeaveCriticalSection(&mutex); } + usleep(1000000); continue; } @@ -113,8 +117,9 @@ static bool setup_device(void) { get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Interface"), &iface); - if(device && iface) + if(device && iface) { logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); + } /* Open registry and look for network adapters */ @@ -123,44 +128,51 @@ static bool setup_device(void) { return false; } - for (i = 0; ; i++) { + for(i = 0; ; i++) { len = sizeof(adapterid); - if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) + + if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) { break; + } /* Find out more about this adapter */ snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) { continue; + } len = sizeof(adaptername); err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len); RegCloseKey(key2); - if(err) + if(err) { continue; + } if(device) { if(!strcmp(device, adapterid)) { found = true; break; - } else + } else { continue; + } } if(iface) { if(!strcmp(iface, adaptername)) { found = true; break; - } else + } else { continue; + } } snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + if(device_handle != INVALID_HANDLE_VALUE) { found = true; break; @@ -174,11 +186,13 @@ static bool setup_device(void) { return false; } - if(!device) + if(!device) { device = xstrdup(adapterid); + } - if(!iface) + if(!iface) { iface = xstrdup(adaptername); + } /* Try to open the corresponding tap device */ @@ -186,7 +200,7 @@ static bool setup_device(void) { snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); } - + if(device_handle == INVALID_HANDLE_VALUE) { logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError())); return false; @@ -245,18 +259,20 @@ static bool write_packet(vpn_packet_t *packet) { static vpn_packet_t queue; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); /* Check if there is something in progress */ if(queue.len) { DWORD size; BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE); + if(success) { ResetEvent(&w_overlapped); queue.len = 0; } else { int err = GetLastError(); + if(err != ERROR_IO_INCOMPLETE) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err)); ResetEvent(&w_overlapped); @@ -275,10 +291,12 @@ static bool write_packet(vpn_packet_t *packet) { if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) { int err = GetLastError(); + if(err != ERROR_IO_PENDING) { logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err)); return false; } + // Write is being done asynchronously. queue.len = packet->len; } else { diff --git a/src/multicast_device.c b/src/multicast_device.c index 5053036..2cc7163 100644 --- a/src/multicast_device.c +++ b/src/multicast_device.c @@ -54,6 +54,7 @@ static bool setup_device(void) { host = xstrdup(device); space = strchr(host, ' '); + if(!space) { logger(LOG_ERR, "Port number required for %s", device_info); free(host); @@ -70,12 +71,14 @@ static bool setup_device(void) { } ai = str2addrinfo(host, port, SOCK_DGRAM); + if(!ai) { free(host); return false; } device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP); + if(device_fd < 0) { logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno)); free(host); @@ -98,54 +101,62 @@ static bool setup_device(void) { switch(ai->ai_family) { #ifdef IP_ADD_MEMBERSHIP - case AF_INET: { - struct ip_mreq mreq; - struct sockaddr_in in; - memcpy(&in, ai->ai_addr, sizeof(in)); - mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq))) { - logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); - closesocket(device_fd); - free(host); - return false; - } + + case AF_INET: { + struct ip_mreq mreq; + struct sockaddr_in in; + memcpy(&in, ai->ai_addr, sizeof(in)); + mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq))) { + logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); + closesocket(device_fd); + free(host); + return false; + } + #ifdef IP_MULTICAST_LOOP - setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof(one)); + setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof(one)); #endif #ifdef IP_MULTICAST_TTL - setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl)); + setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl)); #endif - } break; + } + break; #endif #ifdef IPV6_JOIN_GROUP - case AF_INET6: { - struct ipv6_mreq mreq; - struct sockaddr_in6 in6; - memcpy(&in6, ai->ai_addr, sizeof(in6)); - memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof(mreq.ipv6mr_multiaddr)); - mreq.ipv6mr_interface = in6.sin6_scope_id; - if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof(mreq))) { - logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); - closesocket(device_fd); - free(host); - return false; - } + + case AF_INET6: { + struct ipv6_mreq mreq; + struct sockaddr_in6 in6; + memcpy(&in6, ai->ai_addr, sizeof(in6)); + memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof(mreq.ipv6mr_multiaddr)); + mreq.ipv6mr_interface = in6.sin6_scope_id; + + if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof(mreq))) { + logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); + closesocket(device_fd); + free(host); + return false; + } + #ifdef IPV6_MULTICAST_LOOP - setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof(one)); + setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof(one)); #endif #ifdef IPV6_MULTICAST_HOPS - setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl)); + setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl)); #endif - } break; + } + break; #endif - - default: - logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family); - closesocket(device_fd); - free(host); - return false; + + default: + logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family); + closesocket(device_fd); + free(host); + return false; } free(host); @@ -160,8 +171,9 @@ static void close_device(void) { free(device); free(iface); - if(ai) + if(ai) { freeaddrinfo(ai); + } } static bool read_packet(vpn_packet_t *packet) { @@ -169,7 +181,7 @@ static bool read_packet(vpn_packet_t *packet) { if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) { logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); + device, strerror(errno)); return false; } @@ -184,18 +196,18 @@ static bool read_packet(vpn_packet_t *packet) { device_total_in += packet->len; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, - device_info); + device_info); return true; } static bool write_packet(vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) { logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); + strerror(errno)); return false; } diff --git a/src/net.c b/src/net.c index cac15f9..4b64492 100644 --- a/src/net.c +++ b/src/net.c @@ -3,7 +3,7 @@ Copyright (C) 1998-2005 Ivo Timmermans, 2000-2015 Guus Sliepen 2006 Scott Lamb - 2011 Loïc Grenié + 2011 Loïc Grenié This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,21 +70,26 @@ static void purge(void) { if(!n->status.reachable) { ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name, - n->hostname); + n->hostname); for(snode = n->subnet_tree->head; snode; snode = snext) { snext = snode->next; s = snode->data; send_del_subnet(everyone, s); - if(!strictsubnets) + + if(!strictsubnets) { subnet_del(n, s); + } } for(enode = n->edge_tree->head; enode; enode = enext) { enext = enode->next; e = enode->data; - if(!tunnelserver) + + if(!tunnelserver) { send_del_edge(everyone, e); + } + edge_del(e); } } @@ -101,13 +106,16 @@ static void purge(void) { enext = enode->next; e = enode->data; - if(e->to == n) + if(e->to == n) { break; + } } if(!enode && (!strictsubnets || !n->subnet_tree->head)) /* in strictsubnets mode do not delete nodes with subnets */ + { node_del(n); + } } } } @@ -130,31 +138,45 @@ static int build_fdset(fd_set *readset, fd_set *writeset) { if(c->status.remove) { connection_del(c); - if(!connection_tree->head) + + if(!connection_tree->head) { purge(); + } } else { FD_SET(c->socket, readset); - if(c->outbuflen > 0 || c->status.connecting) + + if(c->outbuflen > 0 || c->status.connecting) { FD_SET(c->socket, writeset); - if(c->socket > max) + } + + if(c->socket > max) { max = c->socket; + } } } for(i = 0; i < listen_sockets; i++) { FD_SET(listen_socket[i].tcp, readset); - if(listen_socket[i].tcp > max) + + if(listen_socket[i].tcp > max) { max = listen_socket[i].tcp; + } + FD_SET(listen_socket[i].udp, readset); - if(listen_socket[i].udp > max) + + if(listen_socket[i].udp > max) { max = listen_socket[i].udp; + } } - if(device_fd >= 0) + if(device_fd >= 0) { FD_SET(device_fd, readset); - if(device_fd > max) + } + + if(device_fd > max) { max = device_fd; - + } + return max; } @@ -166,20 +188,23 @@ static int build_fdset(fd_set *readset, fd_set *writeset) { - Deactivate the host */ void terminate_connection(connection_t *c, bool report) { - if(c->status.remove) + if(c->status.remove) { return; + } ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)", - c->name, c->hostname); + c->name, c->hostname); c->status.remove = true; c->status.active = false; - if(c->node) + if(c->node) { c->node->connection = NULL; + } - if(c->socket) + if(c->socket) { closesocket(c->socket); + } if(c->edge) { if(!c->node) { @@ -188,8 +213,9 @@ void terminate_connection(connection_t *c, bool report) { abort(); } - if(report && !tunnelserver) + if(report && !tunnelserver) { send_del_edge(everyone, c->edge); + } edge_del(c->edge); @@ -202,9 +228,12 @@ void terminate_connection(connection_t *c, bool report) { if(report && !c->node->status.reachable) { edge_t *e; e = lookup_edge(c->node, myself); + if(e) { - if(!tunnelserver) + if(!tunnelserver) { send_del_edge(everyone, e); + } + edge_del(e); } } @@ -216,13 +245,14 @@ void terminate_connection(connection_t *c, bool report) { if(c->outgoing) { c->status.remove = false; - do_outgoing_connection(c); + do_outgoing_connection(c); } #ifndef HAVE_MINGW /* Clean up dead proxy processes */ while(waitpid(-1, NULL, WNOHANG) > 0); + #endif } @@ -246,7 +276,7 @@ static void check_dead_connections(void) { if(c->status.active) { if(c->status.pinged) { ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", - c->name, c->hostname, (long)(now - c->last_ping_time)); + c->name, c->hostname, (long)(now - c->last_ping_time)); c->status.timeout = true; terminate_connection(c, true); } else if(c->last_ping_time + pinginterval <= now) { @@ -255,12 +285,14 @@ static void check_dead_connections(void) { } else { if(c->status.remove) { logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...", - c->name, c->hostname, bitfield_to_int(&c->status, sizeof(c->status))); + c->name, c->hostname, bitfield_to_int(&c->status, sizeof(c->status))); connection_del(c); continue; } + ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", - c->name, c->hostname); + c->name, c->hostname); + if(c->status.connecting) { c->status.connecting = false; closesocket(c->socket); @@ -274,8 +306,8 @@ static void check_dead_connections(void) { if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) { if(c->status.active) { ifdebug(CONNECTIONS) logger(LOG_INFO, - "%s (%s) could not flush for %ld seconds (%d bytes remaining)", - c->name, c->hostname, (long)(now - c->last_flushed_time), c->outbuflen); + "%s (%s) could not flush for %ld seconds (%d bytes remaining)", + c->name, c->hostname, (long)(now - c->last_flushed_time), c->outbuflen); c->status.timeout = true; terminate_connection(c, true); } @@ -287,7 +319,7 @@ static void check_dead_connections(void) { check all connections to see if anything happened on their sockets */ -static void check_network_activity(fd_set * readset, fd_set * writeset) { +static void check_network_activity(fd_set *readset, fd_set *writeset) { connection_t *c; avl_node_t *node; int result, i; @@ -306,6 +338,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) { } else { usleep(errors * 50000); errors++; + if(errors > 10) { logger(LOG_ERR, "Too many errors from %s, exiting!", device); running = false; @@ -317,20 +350,21 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) { for(node = connection_tree->head; node; node = node->next) { c = node->data; - if(c->status.remove) + if(c->status.remove) { continue; + } if(FD_ISSET(c->socket, writeset)) { if(c->status.connecting) { c->status.connecting = false; getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len); - if(!result) + if(!result) { finish_connecting(c); - else { + } else { ifdebug(CONNECTIONS) logger(LOG_DEBUG, - "Error while connecting to %s (%s): %s", - c->name, c->hostname, sockstrerror(result)); + "Error while connecting to %s (%s): %s", + c->name, c->hostname, sockstrerror(result)); closesocket(c->socket); do_outgoing_connection(c); continue; @@ -352,11 +386,13 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) { } for(i = 0; i < listen_sockets; i++) { - if(FD_ISSET(listen_socket[i].udp, readset)) + if(FD_ISSET(listen_socket[i].udp, readset)) { handle_incoming_vpn_data(i); + } - if(FD_ISSET(listen_socket[i].tcp, readset)) + if(FD_ISSET(listen_socket[i].tcp, readset)) { handle_new_meta_connection(listen_socket[i].tcp); + } } } @@ -379,12 +415,15 @@ int main_loop(void) { last_ping_check = now; last_config_check = now; last_graph_dump = now; - + srand(now); #ifdef HAVE_PSELECT - if(lookup_config(config_tree, "GraphDumpFile")) + + if(lookup_config(config_tree, "GraphDumpFile")) { graph_dump = true; + } + /* Block SIGHUP & SIGALRM */ sigemptyset(&block_mask); sigaddset(&block_mask, SIGHUP); @@ -397,16 +436,21 @@ int main_loop(void) { while(running) { #ifdef HAVE_PSELECT next_event = last_ping_check + pingtimeout; - if(graph_dump && next_event > last_graph_dump + 60) + + if(graph_dump && next_event > last_graph_dump + 60) { next_event = last_graph_dump + 60; + } - if((event = peek_next_event()) && next_event > event->time) + if((event = peek_next_event()) && next_event > event->time) { next_event = event->time; + } - if(next_event <= now) + if(next_event <= now) { tv.tv_sec = 0; - else + } else { tv.tv_sec = next_event - now; + } + tv.tv_nsec = 0; #else tv.tv_sec = 1; @@ -436,8 +480,9 @@ int main_loop(void) { } } - if(r > 0) + if(r > 0) { check_network_activity(&readset, &writeset); + } if(do_purge) { purge(); @@ -450,8 +495,9 @@ int main_loop(void) { check_dead_connections(); last_ping_check = now; - if(routing_mode == RMODE_SWITCH) + if(routing_mode == RMODE_SWITCH) { age_subnets(); + } age_past_requests(); @@ -465,6 +511,7 @@ int main_loop(void) { for(node = node_tree->head; node; node = node->next) { n = node->data; + if(n->inkey) { free(n->inkey); n->inkey = NULL; @@ -484,12 +531,16 @@ int main_loop(void) { logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime); usleep(sleeptime * 1000000LL); sleeptime *= 2; - if(sleeptime < 0) + + if(sleeptime < 0) { sleeptime = 3600; + } } else { sleeptime /= 2; - if(sleeptime < 10) + + if(sleeptime < 10) { sleeptime = 10; + } } contradicting_add_edge = 0; @@ -500,11 +551,15 @@ int main_loop(void) { avl_node_t *node; logger(LOG_INFO, "Flushing event queue"); expire_events(); + for(node = connection_tree->head; node; node = node->next) { connection_t *c = node->data; - if(c->status.active) + + if(c->status.active) { send_ping(c); + } } + sigalrm = false; } @@ -518,11 +573,11 @@ int main_loop(void) { avl_node_t *node, *next; char *fname; struct stat s; - + sighup = false; reopenlogger(); - + /* Reread our own configuration file */ exit_configuration(&config_tree); @@ -552,20 +607,24 @@ int main_loop(void) { for(list_node_t *node = outgoing_list->head; node; node = node->next) { outgoing_t *outgoing = node->data; - if(outgoing->event) + if(outgoing->event) { event_del(outgoing->event); + } } list_delete_list(outgoing_list); /* Close connections to hosts that have a changed or deleted host config file */ - + for(node = connection_tree->head; node; node = node->next) { c = node->data; - + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - if(stat(fname, &s) || s.st_mtime > last_config_check) + + if(stat(fname, &s) || s.st_mtime > last_config_check) { terminate_connection(c, c->status.active); + } + free(fname); } @@ -586,26 +645,32 @@ int main_loop(void) { for(node = subnet_tree->head; node; node = next) { next = node->next; subnet = node->data; + if(subnet->expires == 1) { send_del_subnet(everyone, subnet); - if(subnet->owner->status.reachable) + + if(subnet->owner->status.reachable) { subnet_update(subnet->owner, subnet, false); + } + subnet_del(subnet->owner, subnet); } else if(subnet->expires == -1) { subnet->expires = 0; } else { send_add_subnet(everyone, subnet); - if(subnet->owner->status.reachable) + + if(subnet->owner->status.reachable) { subnet_update(subnet->owner, subnet, true); + } } } } /* Try to make outgoing connections */ - + try_outgoing_connections(); } - + /* Dump graph if wanted every 60 seconds*/ if(last_graph_dump + 60 <= now) { diff --git a/src/net.h b/src/net.h index d72de1d..c0e5b31 100644 --- a/src/net.h +++ b/src/net.h @@ -26,15 +26,15 @@ #include "ipv6.h" #ifdef ENABLE_JUMBOGRAMS -#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ +#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #else -#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ +#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #endif -#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ -#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */ +#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ +#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */ -#define MAXSOCKETS 128 /* Overkill... */ +#define MAXSOCKETS 128 /* Overkill... */ typedef struct mac_t { uint8_t x[6]; @@ -77,9 +77,9 @@ typedef union sockaddr_t { #endif typedef struct vpn_packet_t { - length_t len; /* the actual number of bytes in the `data' field */ - int priority; /* priority or TOS */ - uint32_t seqno; /* 32 bits sequence number (network byte order of course) */ + length_t len; /* the actual number of bytes in the `data' field */ + int priority; /* priority or TOS */ + uint32_t seqno; /* 32 bits sequence number (network byte order of course) */ uint8_t data[MAXSIZE]; } vpn_packet_t; diff --git a/src/net_packet.c b/src/net_packet.c index 849c65a..2a419ca 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -85,7 +85,7 @@ void send_mtu_probe(node_t *n) { vpn_packet_t packet; int len, i; int timeout = 1; - + n->mtuprobes++; n->mtuevent = NULL; @@ -114,10 +114,12 @@ void send_mtu_probe(node_t *n) { } if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { - if(n->minmtu > n->maxmtu) + if(n->minmtu > n->maxmtu) { n->minmtu = n->maxmtu; - else + } else { n->maxmtu = n->minmtu; + } + n->mtu = n->minmtu; ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes); n->mtuprobes = 31; @@ -132,8 +134,10 @@ void send_mtu_probe(node_t *n) { for(i = 0; i < 4 + localdiscovery; i++) { if(i == 0) { - if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) + if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) { continue; + } + len = n->maxmtu + 8; } else if(n->maxmtu <= n->minmtu) { len = n->maxmtu; @@ -141,16 +145,19 @@ void send_mtu_probe(node_t *n) { len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu); } - if(len < 64) + if(len < 64) { len = 64; - + } + memset(packet.data, 0, 14); RAND_bytes(packet.data + 14, len - 14); packet.len = len; - if(i >= 4 && n->mtuprobes <= 10) + + if(i >= 4 && n->mtuprobes <= 10) { packet.priority = -1; - else + } else { packet.priority = 0; + } ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname); @@ -173,23 +180,27 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { send_udppacket(n, packet); } else { if(n->mtuprobes > 30) { - if (len == n->maxmtu + 8) { + if(len == n->maxmtu + 8) { ifdebug(TRAFFIC) logger(LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); n->maxmtu = MTU; n->mtuprobes = 10; return; } - if(n->minmtu) + if(n->minmtu) { n->mtuprobes = 30; - else + } else { n->mtuprobes = 1; + } } - if(len > n->maxmtu) + if(len > n->maxmtu) { len = n->maxmtu; - if(n->minmtu < len) + } + + if(n->minmtu < len) { n->minmtu = len; + } } } @@ -208,9 +219,10 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l } else if(level < 10) { #ifdef HAVE_ZLIB unsigned long destlen = MAXSIZE; - if(compress2(dest, &destlen, source, len, level) == Z_OK) + + if(compress2(dest, &destlen, source, len, level) == Z_OK) { return destlen; - else + } else #endif return -1; } else { @@ -222,7 +234,7 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l return -1; #endif } - + return -1; } @@ -233,20 +245,25 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t } else if(level > 9) { #ifdef HAVE_LZO lzo_uint lzolen = MAXSIZE; - if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK) + + if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK) { return lzolen; - else + } else #endif return -1; } + #ifdef HAVE_ZLIB else { unsigned long destlen = MAXSIZE; - if(uncompress(dest, &destlen, source, len) == Z_OK) + + if(uncompress(dest, &destlen, source, len) == Z_OK) { return destlen; - else + } else { return -1; + } } + #endif return -1; @@ -256,7 +273,7 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t static void receive_packet(node_t *n, vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)", - packet->len, n->name, n->hostname); + packet->len, n->name, n->hostname); route(n, packet); } @@ -264,8 +281,9 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) { static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) { unsigned char hmac[EVP_MAX_MD_SIZE]; - if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) + if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) { return false; + } HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL); @@ -283,7 +301,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(!n->inkey) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", - n->name, n->hostname); + n->name, n->hostname); return; } @@ -291,7 +309,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)", - n->name, n->hostname); + n->name, n->hostname); return; } @@ -300,11 +318,11 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(n->indigest && n->inmaclength) { inpkt->len -= n->inmaclength; HMAC(n->indigest, n->inkey, n->inkeylength, - (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL); + (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL); if(memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", - n->name, n->hostname); + n->name, n->hostname); return; } } @@ -315,14 +333,14 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { outpkt = pkt[nextpkt++]; if(!EVP_DecryptInit_ex(n->inctx, NULL, NULL, NULL, NULL) - || !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen, - (unsigned char *) &inpkt->seqno, inpkt->len) - || !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { + || !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen, + (unsigned char *) &inpkt->seqno, inpkt->len) + || !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s", - n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); + n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); return; } - + outpkt->len = outlen + outpad; inpkt = outpkt; } @@ -337,21 +355,23 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(inpkt->seqno >= n->received_seqno + replaywin * 8) { if(n->farfuture++ < replaywin >> 2) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", - n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture); + n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture); return; } + ifdebug(TRAFFIC) logger(LOG_WARNING, "Lost %d packets from %s (%s)", - inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); + inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); memset(n->late, 0, replaywin); - } else if (inpkt->seqno <= n->received_seqno) { + } else if(inpkt->seqno <= n->received_seqno) { if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d", - n->name, n->hostname, inpkt->seqno, n->received_seqno); + n->name, n->hostname, inpkt->seqno, n->received_seqno); return; } } else { - for(i = n->received_seqno + 1; i < inpkt->seqno; i++) + for(i = n->received_seqno + 1; i < inpkt->seqno; i++) { n->late[(i / 8) % replaywin] |= 1 << i % 8; + } } } @@ -359,11 +379,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); } - if(inpkt->seqno > n->received_seqno) + if(inpkt->seqno > n->received_seqno) { n->received_seqno = inpkt->seqno; - - if(n->received_seqno > MAX_SEQNO) + } + + if(n->received_seqno > MAX_SEQNO) { keyexpires = 0; + } /* Decompress the packet */ @@ -374,34 +396,39 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) { ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)", - n->name, n->hostname); + n->name, n->hostname); return; } inpkt = outpkt; - origlen -= MTU/64 + 20; + origlen -= MTU / 64 + 20; } inpkt->priority = 0; - if(!inpkt->data[12] && !inpkt->data[13]) + if(!inpkt->data[12] && !inpkt->data[13]) { mtu_probe_h(n, inpkt, origlen); - else + } else { receive_packet(n, inpkt); + } } void receive_tcppacket(connection_t *c, const char *buffer, int len) { vpn_packet_t outpkt; - if(len > sizeof(outpkt.data)) + if(len > sizeof(outpkt.data)) { return; + } outpkt.len = len; - if(c->options & OPTION_TCPONLY) + + if(c->options & OPTION_TCPONLY) { outpkt.priority = 0; - else + } else { outpkt.priority = -1; + } + memcpy(outpkt.data, buffer, len); receive_packet(c->node, &outpkt); @@ -426,8 +453,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(!n->status.validkey) { ifdebug(TRAFFIC) logger(LOG_INFO, - "No valid key known yet for %s (%s), forwarding via TCP", - n->name, n->hostname); + "No valid key known yet for %s (%s), forwarding via TCP", + n->name, n->hostname); if(n->last_req_key + 10 <= now) { send_req_key(n); @@ -441,13 +468,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) { ifdebug(TRAFFIC) logger(LOG_INFO, - "Packet for %s (%s) larger than minimum MTU, forwarding via %s", - n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP"); + "Packet for %s (%s) larger than minimum MTU, forwarding via %s", + n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP"); - if(n != n->nexthop) + if(n != n->nexthop) { send_packet(n->nexthop, origpkt); - else + } else { send_tcppacket(n->nexthop->connection, origpkt); + } return; } @@ -462,7 +490,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) { ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)", - n->name, n->hostname); + n->name, n->hostname); return; } @@ -480,11 +508,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { outpkt = pkt[nextpkt++]; if(!EVP_EncryptInit_ex(n->outctx, NULL, NULL, NULL, NULL) - || !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen, - (unsigned char *) &inpkt->seqno, inpkt->len) - || !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { + || !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen, + (unsigned char *) &inpkt->seqno, inpkt->len) + || !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s", - n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); + n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); goto end; } @@ -496,7 +524,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(n->outdigest && n->outmaclength) { HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno, - inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL); + inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL); inpkt->len += n->outmaclength; } @@ -523,6 +551,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(origpriority == -1 && n->prevedge) { sock = rand() % listen_sockets; memset(&broadcast, 0, sizeof(broadcast)); + if(listen_socket[sock].sa.sa.sa_family == AF_INET6) { broadcast.in6.sin6_family = AF_INET6; broadcast.in6.sin6_addr.s6_addr[0x0] = 0xff; @@ -535,11 +564,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { broadcast.in.sin_addr.s_addr = -1; broadcast.in.sin_port = n->prevedge->address.in.sin_port; } + sa = &broadcast.sa; sl = SALEN(broadcast.sa); } else { - if(origpriority == -1) + if(origpriority == -1) { origpriority = 0; + } sa = &(n->address.sa); sl = SALEN(n->address.sa); @@ -548,21 +579,31 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(priorityinheritance && origpriority != listen_socket[n->sock].priority) { listen_socket[n->sock].priority = origpriority; + switch(listen_socket[n->sock].sa.sa.sa_family) { #if defined(SOL_IP) && defined(IP_TOS) + case AF_INET: ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority); - if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) /* SO_PRIORITY doesn't seem to work */ + + if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) { /* SO_PRIORITY doesn't seem to work */ logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); + } + break; #endif #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) + case AF_INET6: ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority); - if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority))) + + if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority))) { logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); + } + break; #endif + default: break; } @@ -570,12 +611,16 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { - if(n->maxmtu >= origlen) + if(n->maxmtu >= origlen) { n->maxmtu = origlen - 1; - if(n->mtu >= origlen) + } + + if(n->mtu >= origlen) { n->mtu = origlen - 1; - } else + } + } else { ifdebug(TRAFFIC) logger(LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno)); + } } end: @@ -589,18 +634,20 @@ void send_packet(const node_t *n, vpn_packet_t *packet) { node_t *via; if(n == myself) { - if(overwrite_mac) - memcpy(packet->data, mymac.x, ETH_ALEN); + if(overwrite_mac) { + memcpy(packet->data, mymac.x, ETH_ALEN); + } + devops.write(packet); return; } ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)", - packet->len, n->name, n->hostname); + packet->len, n->name, n->hostname); if(!n->status.reachable) { ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable", - n->name, n->hostname); + n->name, n->hostname); return; } @@ -608,13 +655,15 @@ void send_packet(const node_t *n, vpn_packet_t *packet) { if(via != n) ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)", - n->name, via->name, n->via->hostname); + n->name, via->name, n->via->hostname); if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) { - if(!send_tcppacket(via->connection, packet)) + if(!send_tcppacket(via->connection, packet)) { terminate_connection(via->connection, true); - } else + } + } else { send_udppacket(via, packet); + } } /* Broadcast a packet using the minimum spanning tree */ @@ -625,47 +674,54 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) { node_t *n; // Always give ourself a copy of the packet. - if(from != myself) + if(from != myself) { send_packet(myself, packet); + } // In TunnelServer mode, do not forward broadcast packets. - // The MST might not be valid and create loops. - if(tunnelserver || broadcast_mode == BMODE_NONE) + // The MST might not be valid and create loops. + if(tunnelserver || broadcast_mode == BMODE_NONE) { return; + } ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)", - packet->len, from->name, from->hostname); + packet->len, from->name, from->hostname); switch(broadcast_mode) { - // In MST mode, broadcast packets travel via the Minimum Spanning Tree. - // This guarantees all nodes receive the broadcast packet, and - // usually distributes the sending of broadcast packets over all nodes. - case BMODE_MST: - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - - if(c->status.active && c->status.mst && c != from->nexthop->connection) - send_packet(c->node, packet); + // In MST mode, broadcast packets travel via the Minimum Spanning Tree. + // This guarantees all nodes receive the broadcast packet, and + // usually distributes the sending of broadcast packets over all nodes. + case BMODE_MST: + for(node = connection_tree->head; node; node = node->next) { + c = node->data; + + if(c->status.active && c->status.mst && c != from->nexthop->connection) { + send_packet(c->node, packet); } - break; + } - // In direct mode, we send copies to each node we know of. - // However, this only reaches nodes that can be reached in a single hop. - // We don't have enough information to forward broadcast packets in this case. - case BMODE_DIRECT: - if(from != myself) - break; + break; + + // In direct mode, we send copies to each node we know of. + // However, this only reaches nodes that can be reached in a single hop. + // We don't have enough information to forward broadcast packets in this case. + case BMODE_DIRECT: + if(from != myself) { + break; + } - for(node = node_udp_tree->head; node; node = node->next) { - n = node->data; + for(node = node_udp_tree->head; node; node = node->next) { + n = node->data; - if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n)) - send_packet(n, packet); + if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n)) { + send_packet(n, packet); } - break; + } - default: - break; + break; + + default: + break; } } @@ -678,14 +734,17 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; - if(e->to == myself) + if(e->to == myself) { continue; + } - if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) + if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) { continue; + } - if(!try_mac(e->to, pkt)) + if(!try_mac(e->to, pkt)) { continue; + } n = e->to; break; @@ -705,27 +764,30 @@ void handle_incoming_vpn_data(int sock) { pkt.len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(pkt.len < 0) { - if(!sockwouldblock(sockerrno)) + if(!sockwouldblock(sockerrno)) { logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); + } + return; } - sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */ + sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */ n = lookup_node_udp(&from); if(!n) { n = try_harder(&from, &pkt); - if(n) + + if(n) { update_node_udp(n, &from); - else ifdebug(PROTOCOL) { + } else ifdebug(PROTOCOL) { hostname = sockaddr2hostname(&from); logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname); free(hostname); return; - } - else + } else { return; + } } n->sock = sock; diff --git a/src/net_setup.c b/src/net_setup.c index d0ab464..17c0425 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -50,9 +50,12 @@ devops_t devops; #ifndef HAVE_RSA_SET0_KEY int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { - BN_free(r->n); r->n = n; - BN_free(r->e); r->e = e; - BN_free(r->d); r->d = d; + BN_free(r->n); + r->n = n; + BN_free(r->e); + r->e = e; + BN_free(r->d); + r->d = d; return 1; } #endif @@ -78,14 +81,17 @@ bool read_rsa_public_key(connection_t *c) { logger(LOG_ERR, "Invalid PublicKey for %s!", c->name); return false; } + free(key); BN_hex2bn(&e, "FFFF"); + if(!n || !e || RSA_set0_key(c->rsa_key, n, e, NULL) != 1) { BN_free(e); BN_free(n); logger(LOG_ERR, "RSA_set0_key() failed with PublicKey for %s!", c->name); return false; } + return true; } @@ -105,7 +111,7 @@ bool read_rsa_public_key(connection_t *c) { if(c->rsa_key) { free(pubname); - return true; /* Woohoo. */ + return true; /* Woohoo. */ } /* If it fails, try PEM_read_RSA_PUBKEY. */ @@ -165,8 +171,9 @@ bool read_rsa_public_key(connection_t *c) { // RSA_blinding_on(c->rsa_key, NULL); fclose(fp); - if(c->rsa_key) + if(c->rsa_key) { return true; + } logger(LOG_ERR, "No public key for %s specified!", c->name); @@ -182,26 +189,32 @@ static bool read_rsa_private_key(void) { if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { myself->connection->rsa_key = RSA_new(); + // RSA_blinding_on(myself->connection->rsa_key, NULL); if(BN_hex2bn(&d, key) != strlen(key)) { logger(LOG_ERR, "Invalid PrivateKey for myself!"); free(key); return false; } + free(key); + if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { BN_free(d); logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); return false; } + if(BN_hex2bn(&n, pubkey) != strlen(pubkey)) { free(pubkey); BN_free(d); logger(LOG_ERR, "Invalid PublicKey for myself!"); return false; } + free(pubkey); BN_hex2bn(&e, "FFFF"); + if(!n || !e || !d || RSA_set0_key(myself->connection->rsa_key, n, e, d) != 1) { BN_free(d); BN_free(e); @@ -209,17 +222,19 @@ static bool read_rsa_private_key(void) { logger(LOG_ERR, "RSA_set0_key() failed with PrivateKey for myself!"); return false; } + return true; } - if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) + if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) { xasprintf(&fname, "%s/rsa_key.priv", confbase); + } fp = fopen(fname, "r"); if(!fp) { logger(LOG_ERR, "Error reading RSA private key file `%s': %s", - fname, strerror(errno)); + fname, strerror(errno)); free(fname); return false; } @@ -228,11 +243,13 @@ static bool read_rsa_private_key(void) { struct stat s; if(!fstat(fileno(fp), &s)) { - if(s.st_mode & ~0100700) + if(s.st_mode & ~0100700) { logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); + } } else { logger(LOG_WARNING, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno)); } + #endif myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); @@ -240,7 +257,7 @@ static bool read_rsa_private_key(void) { if(!myself->connection->rsa_key) { logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", - fname, strerror(errno)); + fname, strerror(errno)); free(fname); return false; } @@ -264,6 +281,7 @@ void load_all_subnets(void) { xasprintf(&dname, "%s/hosts", confbase); dir = opendir(dname); + if(!dir) { logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); free(dname); @@ -271,14 +289,15 @@ void load_all_subnets(void) { } while((ent = readdir(dir))) { - if(!check_id(ent->d_name)) + if(!check_id(ent->d_name)) { continue; + } n = lookup_node(ent->d_name); - #ifdef _DIRENT_HAVE_D_TYPE +#ifdef _DIRENT_HAVE_D_TYPE //if(ent->d_type != DT_REG) - // continue; - #endif + // continue; +#endif xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name); init_configuration(&config_tree); @@ -293,8 +312,9 @@ void load_all_subnets(void) { } for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) { - if(!get_config_subnet(cfg, &s)) + if(!get_config_subnet(cfg, &s)) { continue; + } if((s2 = lookup_subnet(n, s))) { s2->expires = -1; @@ -314,31 +334,38 @@ char *get_name(void) { get_config_string(lookup_config(config_tree, "Name"), &name); - if(!name) + if(!name) { return NULL; + } if(*name == '$') { char *envname = getenv(name + 1); char hostname[32] = ""; + if(!envname) { if(strcmp(name + 1, "HOST")) { fprintf(stderr, "Invalid Name: environment variable %s does not exist\n", name + 1); free(name); return false; } + if(gethostname(hostname, sizeof(hostname)) || !*hostname) { fprintf(stderr, "Could not get hostname: %s\n", strerror(errno)); free(name); return false; } + hostname[31] = 0; envname = hostname; } + free(name); name = xstrdup(envname); + for(char *c = name; *c; c++) - if(!isalnum(*c)) + if(!isalnum(*c)) { *c = '_'; + } } if(!check_id(name)) { @@ -391,29 +418,35 @@ static bool setup_myself(void) { read_config_file(config_tree, fname); free(fname); - if(!read_rsa_private_key()) + if(!read_rsa_private_key()) { return false; + } - if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) + if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) { myport = xstrdup("655"); - else + } else { port_specified = true; + } /* Ensure myport is numeric */ if(!atoi(myport)) { struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); sockaddr_t sa; - if(!ai || !ai->ai_addr) + + if(!ai || !ai->ai_addr) { return false; + } + free(myport); memcpy(&sa, ai->ai_addr, ai->ai_addrlen); sockaddr2str(&sa, NULL, &myport); } if(get_config_string(lookup_config(config_tree, "Proxy"), &proxy)) { - if((space = strchr(proxy, ' '))) + if((space = strchr(proxy, ' '))) { *space++ = 0; + } if(!strcasecmp(proxy, "none")) { proxytype = PROXY_NONE; @@ -434,42 +467,56 @@ static bool setup_myself(void) { } switch(proxytype) { - case PROXY_NONE: - default: - break; - - case PROXY_EXEC: - if(!space || !*space) { - logger(LOG_ERR, "Argument expected for proxy type exec!"); - free(proxy); - return false; - } - proxyhost = xstrdup(space); - break; - - case PROXY_SOCKS4: - case PROXY_SOCKS4A: - case PROXY_SOCKS5: - case PROXY_HTTP: - proxyhost = space; - if(space && (space = strchr(space, ' '))) - *space++ = 0, proxyport = space; - if(space && (space = strchr(space, ' '))) - *space++ = 0, proxyuser = space; - if(space && (space = strchr(space, ' '))) - *space++ = 0, proxypass = space; - if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) { - logger(LOG_ERR, "Host and port argument expected for proxy!"); - free(proxy); - return false; - } - proxyhost = xstrdup(proxyhost); - proxyport = xstrdup(proxyport); - if(proxyuser && *proxyuser) - proxyuser = xstrdup(proxyuser); - if(proxypass && *proxypass) - proxypass = xstrdup(proxypass); - break; + case PROXY_NONE: + default: + break; + + case PROXY_EXEC: + if(!space || !*space) { + logger(LOG_ERR, "Argument expected for proxy type exec!"); + free(proxy); + return false; + } + + proxyhost = xstrdup(space); + break; + + case PROXY_SOCKS4: + case PROXY_SOCKS4A: + case PROXY_SOCKS5: + case PROXY_HTTP: + proxyhost = space; + + if(space && (space = strchr(space, ' '))) { + *space++ = 0, proxyport = space; + } + + if(space && (space = strchr(space, ' '))) { + *space++ = 0, proxyuser = space; + } + + if(space && (space = strchr(space, ' '))) { + *space++ = 0, proxypass = space; + } + + if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) { + logger(LOG_ERR, "Host and port argument expected for proxy!"); + free(proxy); + return false; + } + + proxyhost = xstrdup(proxyhost); + proxyport = xstrdup(proxyport); + + if(proxyuser && *proxyuser) { + proxyuser = xstrdup(proxyuser); + } + + if(proxypass && *proxypass) { + proxypass = xstrdup(proxypass); + } + + break; } free(proxy); @@ -480,8 +527,9 @@ static bool setup_myself(void) { cfg = lookup_config(config_tree, "Subnet"); while(cfg) { - if(!get_config_subnet(cfg, &subnet)) + if(!get_config_subnet(cfg, &subnet)) { return false; + } subnet_add(myself, subnet); @@ -490,14 +538,17 @@ static bool setup_myself(void) { /* Check some options */ - if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) + if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) { myself->options |= OPTION_INDIRECT; + } - if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) + if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) { myself->options |= OPTION_TCPONLY; + } - if(myself->options & OPTION_TCPONLY) + if(myself->options & OPTION_TCPONLY) { myself->options |= OPTION_INDIRECT; + } get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets); @@ -506,94 +557,112 @@ static bool setup_myself(void) { strictsubnets |= tunnelserver; if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) { - if(!strcasecmp(mode, "router")) + if(!strcasecmp(mode, "router")) { routing_mode = RMODE_ROUTER; - else if(!strcasecmp(mode, "switch")) + } else if(!strcasecmp(mode, "switch")) { routing_mode = RMODE_SWITCH; - else if(!strcasecmp(mode, "hub")) + } else if(!strcasecmp(mode, "hub")) { routing_mode = RMODE_HUB; - else { + } else { logger(LOG_ERR, "Invalid routing mode!"); free(mode); return false; } + free(mode); } if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { - if(!strcasecmp(mode, "off")) + if(!strcasecmp(mode, "off")) { forwarding_mode = FMODE_OFF; - else if(!strcasecmp(mode, "internal")) + } else if(!strcasecmp(mode, "internal")) { forwarding_mode = FMODE_INTERNAL; - else if(!strcasecmp(mode, "kernel")) + } else if(!strcasecmp(mode, "kernel")) { forwarding_mode = FMODE_KERNEL; - else { + } else { logger(LOG_ERR, "Invalid forwarding mode!"); free(mode); return false; } + free(mode); } choice = true; get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice); - if(choice) + + if(choice) { myself->options |= OPTION_PMTU_DISCOVERY; + } choice = true; get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice); - if(choice) + + if(choice) { myself->options |= OPTION_CLAMP_MSS; + } get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl); + if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) { - if(!strcasecmp(mode, "no")) + if(!strcasecmp(mode, "no")) { broadcast_mode = BMODE_NONE; - else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst")) + } else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst")) { broadcast_mode = BMODE_MST; - else if(!strcasecmp(mode, "direct")) + } else if(!strcasecmp(mode, "direct")) { broadcast_mode = BMODE_DIRECT; - else { + } else { logger(LOG_ERR, "Invalid broadcast mode!"); free(mode); return false; } + free(mode); } #if !defined(SOL_IP) || !defined(IP_TOS) - if(priorityinheritance) + + if(priorityinheritance) { logger(LOG_WARNING, "%s not supported on this platform for IPv4 connection", "PriorityInheritance"); + } + #endif #if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS) - if(priorityinheritance) + + if(priorityinheritance) { logger(LOG_WARNING, "%s not supported on this platform for IPv6 connection", "PriorityInheritance"); + } + #endif - if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) + if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) { macexpire = 600; + } if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) { if(maxtimeout <= 0) { logger(LOG_ERR, "Bogus maximum timeout!"); return false; } - } else + } else { maxtimeout = 900; + } if(get_config_int(lookup_config(config_tree, "MinTimeout"), &mintimeout)) { - if(mintimeout < 0) { - logger(LOG_ERR, "Bogus minimum timeout!"); - return false; - } - if(mintimeout > maxtimeout) { - logger(LOG_WARNING, "Minimum timeout (%d s) cannot be larger than maximum timeout (%d s). Correcting !", mintimeout, maxtimeout ); - mintimeout=maxtimeout; - } - } else - mintimeout = 0; + if(mintimeout < 0) { + logger(LOG_ERR, "Bogus minimum timeout!"); + return false; + } + + if(mintimeout > maxtimeout) { + logger(LOG_WARNING, "Minimum timeout (%d s) cannot be larger than maximum timeout (%d s). Correcting !", mintimeout, maxtimeout); + mintimeout = maxtimeout; + } + } else { + mintimeout = 0; + } if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { if(udp_rcvbuf <= 0) { @@ -614,21 +683,23 @@ static bool setup_myself(void) { logger(LOG_ERR, "ReplayWindow cannot be negative!"); return false; } + replaywin = (unsigned)replaywin_int; } if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) { - if(!strcasecmp(afname, "IPv4")) + if(!strcasecmp(afname, "IPv4")) { addressfamily = AF_INET; - else if(!strcasecmp(afname, "IPv6")) + } else if(!strcasecmp(afname, "IPv6")) { addressfamily = AF_INET6; - else if(!strcasecmp(afname, "any")) + } else if(!strcasecmp(afname, "any")) { addressfamily = AF_UNSPEC; - else { + } else { logger(LOG_ERR, "Invalid address family!"); free(afname); return false; } + free(afname); } @@ -648,14 +719,17 @@ static bool setup_myself(void) { return false; } } + free(cipher); - } else + } else { myself->incipher = EVP_aes_256_cbc(); + } - if(myself->incipher) + if(myself->incipher) { myself->inkeylength = EVP_CIPHER_key_length(myself->incipher) + EVP_CIPHER_iv_length(myself->incipher); - else + } else { myself->inkeylength = 1; + } /* We need to use a stream mode for the meta protocol. Use AES for this, but try to match the key size with the one from the cipher selected @@ -666,18 +740,21 @@ static bool setup_myself(void) { */ int keylen = myself->incipher ? EVP_CIPHER_key_length(myself->incipher) : 0; - if(keylen <= 16) + + if(keylen <= 16) { myself->connection->outcipher = EVP_aes_128_cfb(); - else if(keylen <= 24) + } else if(keylen <= 24) { myself->connection->outcipher = EVP_aes_192_cfb(); - else + } else { myself->connection->outcipher = EVP_aes_256_cfb(); + } - if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) + if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) { keylifetime = 3600; + } keyexpires = now + keylifetime; - + /* Check if we want to use message authentication codes... */ if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) { @@ -694,8 +771,9 @@ static bool setup_myself(void) { } free(digest); - } else + } else { myself->indigest = EVP_sha256(); + } myself->connection->outdigest = EVP_sha256(); @@ -709,8 +787,9 @@ static bool setup_myself(void) { return false; } } - } else + } else { myself->inmaclength = 4; + } myself->connection->outmaclength = 0; @@ -721,8 +800,9 @@ static bool setup_myself(void) { logger(LOG_ERR, "Bogus compression level!"); return false; } - } else + } else { myself->incompression = 0; + } myself->connection->outcompression = 0; @@ -735,33 +815,41 @@ static bool setup_myself(void) { graph(); - if(strictsubnets) + if(strictsubnets) { load_all_subnets(); + } /* Open device */ devops = os_devops; if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { - if(!strcasecmp(type, "dummy")) + if(!strcasecmp(type, "dummy")) { devops = dummy_devops; - else if(!strcasecmp(type, "raw_socket")) + } else if(!strcasecmp(type, "raw_socket")) { devops = raw_socket_devops; - else if(!strcasecmp(type, "multicast")) + } else if(!strcasecmp(type, "multicast")) { devops = multicast_devops; + } + #ifdef ENABLE_UML - else if(!strcasecmp(type, "uml")) + else if(!strcasecmp(type, "uml")) { devops = uml_devops; + } + #endif #ifdef ENABLE_VDE - else if(!strcasecmp(type, "vde")) + else if(!strcasecmp(type, "vde")) { devops = vde_devops; + } + #endif free(type); } - if(!devops.setup()) + if(!devops.setup()) { return false; + } /* Run tinc-up script to further initialize the tap interface */ xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); @@ -777,8 +865,9 @@ static bool setup_myself(void) { #endif execute_script("tinc-up", envp); - for(i = 0; i < 4; i++) + for(i = 0; i < 4; i++) { free(envp[i]); + } /* Run subnet-up scripts for our own subnets */ @@ -802,6 +891,7 @@ static bool setup_myself(void) { for(i = 0; i < listen_sockets; i++) { salen = sizeof(sa); + if(getsockname(i + 3, &sa.sa, &salen) < 0) { logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno)); return false; @@ -810,12 +900,14 @@ static bool setup_myself(void) { listen_socket[i].tcp = i + 3; #ifdef FD_CLOEXEC - fcntl(i + 3, F_SETFD, FD_CLOEXEC); + fcntl(i + 3, F_SETFD, FD_CLOEXEC); #endif listen_socket[i].udp = setup_vpn_in_socket(&sa); - if(listen_socket[i].udp < 0) + + if(listen_socket[i].udp < 0) { return false; + } ifdebug(CONNECTIONS) { hostname = sockaddr2hostname(&sa); @@ -831,20 +923,24 @@ static bool setup_myself(void) { do { get_config_string(cfg, &address); - if(cfg) + + if(cfg) { cfg = lookup_config_next(config_tree, cfg); + } char *port = myport; if(address) { char *space = strchr(address, ' '); + if(space) { *space++ = 0; port = space; } - if(!strcmp(address, "*")) + if(!strcmp(address, "*")) { *address = 0; + } } hint.ai_family = addressfamily; @@ -861,7 +957,7 @@ static bool setup_myself(void) { if(err || !ai) { logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", - gai_strerror(err)); + gai_strerror(err)); return false; } @@ -872,16 +968,18 @@ static bool setup_myself(void) { } listen_socket[listen_sockets].tcp = - setup_listen_socket((sockaddr_t *) aip->ai_addr); + setup_listen_socket((sockaddr_t *) aip->ai_addr); - if(listen_socket[listen_sockets].tcp < 0) + if(listen_socket[listen_sockets].tcp < 0) { continue; + } listen_socket[listen_sockets].udp = - setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); + setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); - if(listen_socket[listen_sockets].udp < 0) + if(listen_socket[listen_sockets].udp < 0) { continue; + } ifdebug(CONNECTIONS) { hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); @@ -907,11 +1005,14 @@ static bool setup_myself(void) { if(!port_specified) { sockaddr_t sa; socklen_t salen = sizeof(sa); + if(!getsockname(listen_socket[0].udp, &sa.sa, &salen)) { free(myport); sockaddr2str(&sa, NULL, &myport); - if(!myport) + + if(!myport) { myport = xstrdup("655"); + } } } @@ -938,19 +1039,25 @@ bool setup_network(void) { if(pinginterval < 1) { pinginterval = 86400; } - } else + } else { pinginterval = 60; + } - if(!get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout)) + if(!get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout)) { pingtimeout = 5; - if(pingtimeout < 1 || pingtimeout > pinginterval) + } + + if(pingtimeout < 1 || pingtimeout > pinginterval) { pingtimeout = pinginterval; + } - if(!get_config_int(lookup_config(config_tree, "MaxOutputBufferSize"), &maxoutbufsize)) + if(!get_config_int(lookup_config(config_tree, "MaxOutputBufferSize"), &maxoutbufsize)) { maxoutbufsize = 10 * MTU; + } - if(!setup_myself()) + if(!setup_myself()) { return false; + } return true; } @@ -974,8 +1081,9 @@ void close_network_connections(void) { for(list_node_t *node = outgoing_list->head; node; node = node->next) { outgoing_t *outgoing = node->data; - if(outgoing->event) + if(outgoing->event) { event_del(outgoing->event); + } } list_delete_list(outgoing_list); @@ -1005,10 +1113,13 @@ void close_network_connections(void) { execute_script("tinc-down", envp); - if(myport) free(myport); + if(myport) { + free(myport); + } - for(i = 0; i < 4; i++) + for(i = 0; i < 4; i++) { free(envp[i]); + } devops.close(); diff --git a/src/net_socket.c b/src/net_socket.c index 1497a8d..6b3c7d2 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -62,12 +62,14 @@ static void configure_tcp(connection_t *c) { if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) { logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno)); } + #elif defined(WIN32) unsigned long arg = 1; if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) { logger(LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno)); } + #endif #if defined(SOL_TCP) && defined(TCP_NODELAY) @@ -94,8 +96,9 @@ static bool bind_to_interface(int sd) { int status; #endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */ - if(!get_config_string(lookup_config (config_tree, "BindToInterface"), &iface)) + if(!get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) { return true; + } #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) memset(&ifr, 0, sizeof(ifr)); @@ -104,6 +107,7 @@ static bool bind_to_interface(int sd) { free(iface); status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)); + if(status) { logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_ifrn.ifrn_name, strerror(errno)); return false; @@ -139,8 +143,11 @@ int setup_listen_socket(const sockaddr_t *sa) { setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) - if(sa->sa.sa_family == AF_INET6) + + if(sa->sa.sa_family == AF_INET6) { setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option)); + } + #endif if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) { @@ -203,13 +210,14 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { closesocket(nfd); logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", - strerror(errno)); + strerror(errno)); return -1; } } #elif defined(WIN32) { unsigned long arg = 1; + if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { closesocket(nfd); logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno)); @@ -222,15 +230,20 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option)); - if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) + if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) { logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno)); + } - if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) + if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) { logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno)); + } #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) - if(sa->sa.sa_family == AF_INET6) + + if(sa->sa.sa_family == AF_INET6) { setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option)); + } + #endif #if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT) @@ -238,30 +251,38 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { #endif #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) + if(myself->options & OPTION_PMTU_DISCOVERY) { option = IP_PMTUDISC_DO; setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); } + #elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT) + if(myself->options & OPTION_PMTU_DISCOVERY) { option = 1; setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option)); } + #endif #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) + if(myself->options & OPTION_PMTU_DISCOVERY) { option = IPV6_PMTUDISC_DO; setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); } + #elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG) + if(myself->options & OPTION_PMTU_DISCOVERY) { option = 1; setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option)); } + #endif - if (!bind_to_interface(nfd)) { + if(!bind_to_interface(nfd)) { closesocket(nfd); return -1; } @@ -280,14 +301,18 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { void retry_outgoing(outgoing_t *outgoing) { outgoing->timeout += 5; - if(outgoing->timeout < mintimeout) + if(outgoing->timeout < mintimeout) { outgoing->timeout = mintimeout; + } - if(outgoing->timeout > maxtimeout) + if(outgoing->timeout > maxtimeout) { outgoing->timeout = maxtimeout; + } - if(outgoing->event) + if(outgoing->event) { event_del(outgoing->event); + } + outgoing->event = new_event(); outgoing->event->handler = (event_handler_t) setup_outgoing_connection; outgoing->event->time = now + outgoing->timeout; @@ -295,8 +320,8 @@ void retry_outgoing(outgoing_t *outgoing) { event_add(outgoing->event); ifdebug(CONNECTIONS) logger(LOG_NOTICE, - "Trying to re-establish outgoing connection in %d seconds", - outgoing->timeout); + "Trying to re-establish outgoing connection in %d seconds", + outgoing->timeout); } void finish_connecting(connection_t *c) { @@ -340,14 +365,19 @@ static void do_outgoing_pipe(connection_t *c, char *command) { setenv("REMOTEPORT", port, true); setenv("NODE", c->name, true); setenv("NAME", myself->name, true); - if(netname) + + if(netname) { setenv("NETNAME", netname, true); + } int result = system(command); - if(result < 0) + + if(result < 0) { logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno)); - else if(result) + } else if(result) { logger(LOG_ERR, "%s exited with non-zero status %d", command, result); + } + exit(result); #else logger(LOG_ERR, "Proxy type exec not supported on this platform!"); @@ -357,12 +387,14 @@ static void do_outgoing_pipe(connection_t *c, char *command) { static bool is_valid_host_port(const char *host, const char *port) { for(const char *p = host; *p; p++) - if(!isalnum(*p) && *p != '-' && *p != '.') + if(!isalnum(*p) && *p != '-' && *p != '.') { return false; + } for(const char *p = port; *p; p++) - if(!isalnum(*p)) + if(!isalnum(*p)) { return false; + } return true; } @@ -377,10 +409,11 @@ void do_outgoing_connection(connection_t *c) { } begin: + if(!c->outgoing->ai) { if(!c->outgoing->cfg) { ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s", - c->name); + c->name); c->status.remove = true; retry_outgoing(c->outgoing); c->outgoing = NULL; @@ -392,12 +425,14 @@ begin: get_config_string(c->outgoing->cfg, &address); space = strchr(address, ' '); + if(space) { port = xstrdup(space + 1); *space = 0; } else { - if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) + if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) { port = xstrdup("655"); + } } c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM); @@ -416,13 +451,16 @@ begin: c->outgoing->aip = c->outgoing->ai; c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg); - if(!c->outgoing->ai && proxytype != PROXY_NONE) + if(!c->outgoing->ai && proxytype != PROXY_NONE) { goto connect; + } } if(!c->outgoing->aip) { - if(c->outgoing->ai) + if(c->outgoing->ai) { freeaddrinfo(c->outgoing->ai); + } + c->outgoing->ai = NULL; goto begin; } @@ -431,13 +469,15 @@ begin: c->outgoing->aip = c->outgoing->aip->ai_next; connect: - if(c->hostname) + + if(c->hostname) { free(c->hostname); + } c->hostname = sockaddr2hostname(&c->address); ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name, - c->hostname); + c->hostname); if(!proxytype) { c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); @@ -446,8 +486,11 @@ connect: do_outgoing_pipe(c, proxyhost); } else { proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM); - if(!proxyai) + + if(!proxyai) { goto begin; + } + ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport); c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP); } @@ -457,8 +500,9 @@ connect: goto begin; } - if(proxytype != PROXY_EXEC) + if(proxytype != PROXY_EXEC) { configure_tcp(c); + } #ifdef FD_CLOEXEC fcntl(c->socket, F_SETFD, FD_CLOEXEC); @@ -467,8 +511,11 @@ connect: if(proxytype != PROXY_EXEC) { #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) int option = 1; - if(c->address.sa.sa_family == AF_INET6) + + if(c->address.sa.sa_family == AF_INET6) { setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option)); + } + #endif bind_to_interface(c->socket); @@ -488,10 +535,12 @@ connect: if(b != -1) { sockaddr_t sa = listen_socket[b].sa; - if(sa.sa.sa_family == AF_INET) + + if(sa.sa.sa_family == AF_INET) { sa.in.sin_port = 0; - else if(sa.sa.sa_family == AF_INET6) + } else if(sa.sa.sa_family == AF_INET6) { sa.in6.sin6_port = 0; + } if(bind(c->socket, &sa.sa, SALEN(sa.sa))) { char *addrstr = sockaddr2hostname(&sa); @@ -557,6 +606,7 @@ void setup_outgoing_connection(outgoing_t *outgoing) { c->outcompression = myself->connection->outcompression; init_configuration(&c->config_tree); + if(!read_connection_config(c)) { free_connection(c); outgoing->timeout = maxtimeout; @@ -626,11 +676,13 @@ bool handle_new_meta_connection(int sock) { } static void free_outgoing(outgoing_t *outgoing) { - if(outgoing->ai) + if(outgoing->ai) { freeaddrinfo(outgoing->ai); + } - if(outgoing->name) + if(outgoing->name) { free(outgoing->name); + } free(outgoing); } @@ -639,16 +691,16 @@ void try_outgoing_connections(void) { static config_t *cfg = NULL; char *name; outgoing_t *outgoing; - + outgoing_list = list_alloc((list_action_t)free_outgoing); - + for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) { get_config_string(cfg, &name); if(!check_id(name)) { logger(LOG_ERR, - "Invalid name for outgoing connection in %s line %d", - cfg->file, cfg->line); + "Invalid name for outgoing connection in %s line %d", + cfg->file, cfg->line); free(name); continue; } diff --git a/src/netutl.c b/src/netutl.c index e473f17..abe3d87 100644 --- a/src/netutl.c +++ b/src/netutl.c @@ -47,7 +47,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock if(err) { logger(LOG_WARNING, "Error looking up %s port %s: %s", address, - service, gai_strerror(err)); + service, gai_strerror(err)); return NULL; } @@ -67,7 +67,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port) { if(err || !ai) { ifdebug(SCARY_THINGS) - logger(LOG_DEBUG, "Unknown type address %s port %s", address, port); + logger(LOG_DEBUG, "Unknown type address %s port %s", address, port); result.sa.sa_family = AF_UNKNOWN; result.unknown.address = xstrdup(address); result.unknown.port = xstrdup(port); @@ -87,10 +87,14 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) { int err; if(sa->sa.sa_family == AF_UNKNOWN) { - if(addrstr) + if(addrstr) { *addrstr = xstrdup(sa->unknown.address); - if(portstr) + } + + if(portstr) { *portstr = xstrdup(sa->unknown.port); + } + return; } @@ -98,19 +102,23 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) { if(err) { logger(LOG_ERR, "Error while translating addresses: %s", - gai_strerror(err)); + gai_strerror(err)); abort(); } scopeid = strchr(address, '%'); - if(scopeid) - *scopeid = '\0'; /* Descope. */ + if(scopeid) { + *scopeid = '\0'; /* Descope. */ + } - if(addrstr) + if(addrstr) { *addrstr = xstrdup(address); - if(portstr) + } + + if(portstr) { *portstr = xstrdup(port); + } } char *sockaddr2hostname(const sockaddr_t *sa) { @@ -125,10 +133,11 @@ char *sockaddr2hostname(const sockaddr_t *sa) { } err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), - hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); + hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); + if(err) { logger(LOG_ERR, "Error while looking up hostname: %s", - gai_strerror(err)); + gai_strerror(err)); } xasprintf(&str, "%s port %s", address, port); @@ -141,26 +150,27 @@ int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) { result = a->sa.sa_family - b->sa.sa_family; - if(result) + if(result) { return result; + } - switch (a->sa.sa_family) { - case AF_UNSPEC: - return 0; + switch(a->sa.sa_family) { + case AF_UNSPEC: + return 0; - case AF_UNKNOWN: - return strcmp(a->unknown.address, b->unknown.address); + case AF_UNKNOWN: + return strcmp(a->unknown.address, b->unknown.address); - case AF_INET: - return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); + case AF_INET: + return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); - case AF_INET6: - return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); + case AF_INET6: + return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); - default: - logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", - a->sa.sa_family); - abort(); + default: + logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", + a->sa.sa_family); + abort(); } } @@ -169,41 +179,45 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) { result = a->sa.sa_family - b->sa.sa_family; - if(result) + if(result) { return result; + } - switch (a->sa.sa_family) { - case AF_UNSPEC: - return 0; + switch(a->sa.sa_family) { + case AF_UNSPEC: + return 0; - case AF_UNKNOWN: - result = strcmp(a->unknown.address, b->unknown.address); + case AF_UNKNOWN: + result = strcmp(a->unknown.address, b->unknown.address); - if(result) - return result; + if(result) { + return result; + } - return strcmp(a->unknown.port, b->unknown.port); + return strcmp(a->unknown.port, b->unknown.port); - case AF_INET: - result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); + case AF_INET: + result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); - if(result) - return result; + if(result) { + return result; + } - return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port)); + return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port)); - case AF_INET6: - result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); + case AF_INET6: + result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); - if(result) - return result; + if(result) { + return result; + } - return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port)); + return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port)); - default: - logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", - a->sa.sa_family); - abort(); + default: + logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", + a->sa.sa_family); + abort(); } } @@ -223,7 +237,7 @@ void sockaddrfree(sockaddr_t *a) { free(a->unknown.port); } } - + void sockaddrunmap(sockaddr_t *sa) { if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) { sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3]; @@ -233,20 +247,26 @@ void sockaddrunmap(sockaddr_t *sa) { void sockaddr_setport(sockaddr_t *sa, const char *port) { uint16_t portnum = htons(atoi(port)); - if(!portnum) + + if(!portnum) { return; + } + switch(sa->sa.sa_family) { - case AF_INET: - sa->in.sin_port = portnum; - break; - case AF_INET6: - sa->in6.sin6_port = portnum; - break; - case AF_UNKNOWN: - free(sa->unknown.port); - sa->unknown.port = xstrdup(port); - default: - return; + case AF_INET: + sa->in.sin_port = portnum; + break; + + case AF_INET6: + sa->in6.sin6_port = portnum; + break; + + case AF_UNKNOWN: + free(sa->unknown.port); + sa->unknown.port = xstrdup(port); + + default: + return; } } @@ -259,13 +279,15 @@ int maskcmp(const void *va, const void *vb, int masklen) { for(m = masklen, i = 0; m >= 8; m -= 8, i++) { result = a[i] - b[i]; - if(result) + + if(result) { return result; + } } if(m) return (a[i] & (0x100 - (1 << (8 - m)))) - - (b[i] & (0x100 - (1 << (8 - m)))); + (b[i] & (0x100 - (1 << (8 - m)))); return 0; } @@ -277,11 +299,13 @@ void mask(void *va, int masklen, int len) { i = masklen / 8; masklen %= 8; - if(masklen) + if(masklen) { a[i++] &= (0x100 - (1 << (8 - masklen))); + } - for(; i < len; i++) + for(; i < len; i++) { a[i] = 0; + } } void maskcpy(void *va, const void *vb, int masklen, int len) { @@ -289,16 +313,18 @@ void maskcpy(void *va, const void *vb, int masklen, int len) { char *a = va; const char *b = vb; - for(m = masklen, i = 0; m >= 8; m -= 8, i++) + for(m = masklen, i = 0; m >= 8; m -= 8, i++) { a[i] = b[i]; + } if(m) { a[i] = b[i] & (0x100 - (1 << (8 - m))); i++; } - for(; i < len; i++) + for(; i < len; i++) { a[i] = 0; + } } bool maskcheck(const void *va, int masklen, int len) { @@ -308,12 +334,14 @@ bool maskcheck(const void *va, int masklen, int len) { i = masklen / 8; masklen %= 8; - if(masklen && a[i++] & (0xff >> masklen)) + if(masklen && a[i++] & (0xff >> masklen)) { return false; + } for(; i < len; i++) - if(a[i] != 0) + if(a[i] != 0) { return false; + } return true; } diff --git a/src/node.c b/src/node.c index 23ebd8d..720f081 100644 --- a/src/node.c +++ b/src/node.c @@ -28,8 +28,8 @@ #include "utils.h" #include "xalloc.h" -avl_tree_t *node_tree; /* Known nodes, sorted by name */ -avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ +avl_tree_t *node_tree; /* Known nodes, sorted by name */ +avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ node_t *myself; @@ -38,7 +38,7 @@ static int node_compare(const node_t *a, const node_t *b) { } static int node_udp_compare(const node_t *a, const node_t *b) { - return sockaddrcmp(&a->address, &b->address); + return sockaddrcmp(&a->address, &b->address); } void init_nodes(void) { @@ -54,13 +54,19 @@ void exit_nodes(void) { node_t *new_node(void) { node_t *n = xmalloc_and_zero(sizeof(*n)); - if(replaywin) n->late = xmalloc_and_zero(replaywin); + if(replaywin) { + n->late = xmalloc_and_zero(replaywin); + } + n->subnet_tree = new_subnet_tree(); n->edge_tree = new_edge_tree(); n->inctx = EVP_CIPHER_CTX_new(); n->outctx = EVP_CIPHER_CTX_new(); - if(!n->inctx || !n->outctx) + + if(!n->inctx || !n->outctx) { abort(); + } + n->mtu = MTU; n->maxmtu = MTU; @@ -68,34 +74,42 @@ node_t *new_node(void) { } void free_node(node_t *n) { - if(n->inkey) + if(n->inkey) { free(n->inkey); + } - if(n->outkey) + if(n->outkey) { free(n->outkey); + } - if(n->subnet_tree) + if(n->subnet_tree) { free_subnet_tree(n->subnet_tree); + } - if(n->edge_tree) + if(n->edge_tree) { free_edge_tree(n->edge_tree); + } sockaddrfree(&n->address); EVP_CIPHER_CTX_free(n->outctx); EVP_CIPHER_CTX_free(n->inctx); - if(n->mtuevent) + if(n->mtuevent) { event_del(n->mtuevent); - - if(n->hostname) + } + + if(n->hostname) { free(n->hostname); + } - if(n->name) + if(n->name) { free(n->name); + } - if(n->late) + if(n->late) { free(n->late); + } free(n); } @@ -150,8 +164,9 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) { avl_delete(node_udp_tree, n); - if(n->hostname) + if(n->hostname) { free(n->hostname); + } if(sa) { n->address = *sa; @@ -174,10 +189,10 @@ void dump_nodes(void) { for(node = node_tree->head; node; node = node->next) { n = node->data; logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s pmtu %d (min %d max %d)", - n->name, n->hostname, n->outcipher ? EVP_CIPHER_nid(n->outcipher) : 0, - n->outdigest ? EVP_MD_type(n->outdigest) : 0, n->outmaclength, n->outcompression, - n->options, bitfield_to_int(&n->status, sizeof(n->status)), n->nexthop ? n->nexthop->name : "-", - n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu); + n->name, n->hostname, n->outcipher ? EVP_CIPHER_nid(n->outcipher) : 0, + n->outdigest ? EVP_MD_type(n->outdigest) : 0, n->outmaclength, n->outcompression, + n->options, bitfield_to_int(&n->status, sizeof(n->status)), n->nexthop ? n->nexthop->name : "-", + n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu); } logger(LOG_DEBUG, "End of nodes."); diff --git a/src/node.h b/src/node.h index 14713b2..6226ae9 100644 --- a/src/node.h +++ b/src/node.h @@ -27,65 +27,65 @@ #include "subnet.h" typedef struct node_status_t { - unsigned int unused_active:1; /* 1 if active (not used for nodes) */ - unsigned int validkey:1; /* 1 if we currently have a valid key for him */ - unsigned int unused_waitingforkey:1; /* 1 if we already sent out a request */ - unsigned int visited:1; /* 1 if this node has been visited by one of the graph algorithms */ - unsigned int reachable:1; /* 1 if this node is reachable in the graph */ - unsigned int indirect:1; /* 1 if this node is not directly reachable by us */ - unsigned int unused:26; + unsigned int unused_active: 1; /* 1 if active (not used for nodes) */ + unsigned int validkey: 1; /* 1 if we currently have a valid key for him */ + unsigned int unused_waitingforkey: 1; /* 1 if we already sent out a request */ + unsigned int visited: 1; /* 1 if this node has been visited by one of the graph algorithms */ + unsigned int reachable: 1; /* 1 if this node is reachable in the graph */ + unsigned int indirect: 1; /* 1 if this node is not directly reachable by us */ + unsigned int unused: 26; } node_status_t; typedef struct node_t { - char *name; /* name of this node */ - uint32_t options; /* options turned on for this node */ + char *name; /* name of this node */ + uint32_t options; /* options turned on for this node */ - int sock; /* Socket to use for outgoing UDP packets */ - sockaddr_t address; /* his real (internet) ip to send UDP packets to */ - char *hostname; /* the hostname of its real ip */ + int sock; /* Socket to use for outgoing UDP packets */ + sockaddr_t address; /* his real (internet) ip to send UDP packets to */ + char *hostname; /* the hostname of its real ip */ node_status_t status; time_t last_req_key; - const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */ - char *inkey; /* Cipher key and iv */ - int inkeylength; /* Cipher key and iv length */ - EVP_CIPHER_CTX *inctx; /* Cipher context */ - - const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/ - char *outkey; /* Cipher key and iv */ - int outkeylength; /* Cipher key and iv length */ - EVP_CIPHER_CTX *outctx; /* Cipher context */ - - const EVP_MD *indigest; /* Digest type for MAC of packets received from him */ - int inmaclength; /* Length of MAC */ - - const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/ - int outmaclength; /* Length of MAC */ - - int incompression; /* Compressionlevel, 0 = no compression */ - int outcompression; /* Compressionlevel, 0 = no compression */ - - struct node_t *nexthop; /* nearest node from us to him */ - struct edge_t *prevedge; /* nearest node from him to us */ - struct node_t *via; /* next hop for UDP packets */ - - avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ - - avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ - - struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ - - uint32_t sent_seqno; /* Sequence number last sent to this node */ - uint32_t received_seqno; /* Sequence number last received from this node */ - uint32_t farfuture; /* Packets in a row that have arrived from the far future */ - unsigned char* late; /* Bitfield marking late packets */ - - length_t mtu; /* Maximum size of packets to send to this node */ - length_t minmtu; /* Probed minimum MTU */ - length_t maxmtu; /* Probed maximum MTU */ - int mtuprobes; /* Number of probes */ - event_t *mtuevent; /* Probe event */ + const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */ + char *inkey; /* Cipher key and iv */ + int inkeylength; /* Cipher key and iv length */ + EVP_CIPHER_CTX *inctx; /* Cipher context */ + + const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/ + char *outkey; /* Cipher key and iv */ + int outkeylength; /* Cipher key and iv length */ + EVP_CIPHER_CTX *outctx; /* Cipher context */ + + const EVP_MD *indigest; /* Digest type for MAC of packets received from him */ + int inmaclength; /* Length of MAC */ + + const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/ + int outmaclength; /* Length of MAC */ + + int incompression; /* Compressionlevel, 0 = no compression */ + int outcompression; /* Compressionlevel, 0 = no compression */ + + struct node_t *nexthop; /* nearest node from us to him */ + struct edge_t *prevedge; /* nearest node from him to us */ + struct node_t *via; /* next hop for UDP packets */ + + avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ + + avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ + + struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ + + uint32_t sent_seqno; /* Sequence number last sent to this node */ + uint32_t received_seqno; /* Sequence number last received from this node */ + uint32_t farfuture; /* Packets in a row that have arrived from the far future */ + unsigned char *late; /* Bitfield marking late packets */ + + length_t mtu; /* Maximum size of packets to send to this node */ + length_t minmtu; /* Probed minimum MTU */ + length_t maxmtu; /* Probed maximum MTU */ + int mtuprobes; /* Number of probes */ + event_t *mtuevent; /* Probe event */ } node_t; extern struct node_t *myself; @@ -94,7 +94,7 @@ extern avl_tree_t *node_udp_tree; extern void init_nodes(void); extern void exit_nodes(void); -extern node_t *new_node(void) __attribute__ ((__malloc__)); +extern node_t *new_node(void) __attribute__((__malloc__)); extern void free_node(node_t *); extern void node_add(node_t *); extern void node_del(node_t *); diff --git a/src/pidfile.c b/src/pidfile.c index 232c2c4..dd17267 100644 --- a/src/pidfile.c +++ b/src/pidfile.c @@ -22,7 +22,7 @@ /* left unaltered for tinc -- Ivo Timmermans */ /* * Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze - * First version (v0.2) released + * First version (v0.2) released */ #include "system.h" @@ -36,17 +36,20 @@ * 0 is returned if either there's no pidfile, it's empty * or no pid can be read. */ -pid_t read_pid (const char *pidfile) -{ - FILE *f; - long pid; - - if (!(f=fopen(pidfile,"r"))) - return 0; - if(fscanf(f,"%20ld", &pid) != 1) - pid = 0; - fclose(f); - return (pid_t)pid; +pid_t read_pid(const char *pidfile) { + FILE *f; + long pid; + + if(!(f = fopen(pidfile, "r"))) { + return 0; + } + + if(fscanf(f, "%20ld", &pid) != 1) { + pid = 0; + } + + fclose(f); + return (pid_t)pid; } /* check_pid @@ -55,25 +58,27 @@ pid_t read_pid (const char *pidfile) * table (using /proc) to determine if the process already exists. If * so the pid is returned, otherwise 0. */ -pid_t check_pid (const char *pidfile) -{ - pid_t pid = read_pid(pidfile); - - /* Amazing ! _I_ am already holding the pid file... */ - if ((!pid) || (pid == getpid ())) - return 0; - - /* - * The 'standard' method of doing this is to try and do a 'fake' kill - * of the process. If an ESRCH error is returned the process cannot - * be found -- GW - */ - /* But... errno is usually changed only on error.. */ - errno = 0; - if (kill(pid, 0) && errno == ESRCH) - return 0; - - return pid; +pid_t check_pid(const char *pidfile) { + pid_t pid = read_pid(pidfile); + + /* Amazing ! _I_ am already holding the pid file... */ + if((!pid) || (pid == getpid())) { + return 0; + } + + /* + * The 'standard' method of doing this is to try and do a 'fake' kill + * of the process. If an ESRCH error is returned the process cannot + * be found -- GW + */ + /* But... errno is usually changed only on error.. */ + errno = 0; + + if(kill(pid, 0) && errno == ESRCH) { + return 0; + } + + return pid; } /* write_pid @@ -81,44 +86,49 @@ pid_t check_pid (const char *pidfile) * Writes the pid to the specified file. If that fails 0 is * returned, otherwise the pid. */ -pid_t write_pid (const char *pidfile) -{ - FILE *f; - int fd; - pid_t pid; - - if ((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1) { - return 0; - } - - if ((f = fdopen(fd, "r+")) == NULL) { - close(fd); - return 0; - } - +pid_t write_pid(const char *pidfile) { + FILE *f; + int fd; + pid_t pid; + + if((fd = open(pidfile, O_RDWR | O_CREAT, 0644)) == -1) { + return 0; + } + + if((f = fdopen(fd, "r+")) == NULL) { + close(fd); + return 0; + } + #ifdef HAVE_FLOCK - if (flock(fd, LOCK_EX|LOCK_NB) == -1) { - fclose(f); - return 0; - } + + if(flock(fd, LOCK_EX | LOCK_NB) == -1) { + fclose(f); + return 0; + } + #endif - pid = getpid(); - if (!fprintf(f,"%ld\n", (long)pid)) { - fclose(f); - return 0; - } - fflush(f); + pid = getpid(); + + if(!fprintf(f, "%ld\n", (long)pid)) { + fclose(f); + return 0; + } + + fflush(f); #ifdef HAVE_FLOCK - if (flock(fd, LOCK_UN) == -1) { - fclose(f); - return 0; - } + + if(flock(fd, LOCK_UN) == -1) { + fclose(f); + return 0; + } + #endif - fclose(f); + fclose(f); - return pid; + return pid; } /* remove_pid @@ -126,8 +136,7 @@ pid_t write_pid (const char *pidfile) * Remove the the specified file. The result from unlink(2) * is returned */ -int remove_pid (const char *pidfile) -{ - return unlink (pidfile); +int remove_pid(const char *pidfile) { + return unlink(pidfile); } #endif diff --git a/src/pidfile.h b/src/pidfile.h index ed539e3..7d71cc2 100644 --- a/src/pidfile.h +++ b/src/pidfile.h @@ -29,7 +29,7 @@ * 0 is returned if either there's no pidfile, it's empty * or no pid can be read. */ -extern pid_t read_pid (const char *pidfile); +extern pid_t read_pid(const char *pidfile); /* check_pid * @@ -37,21 +37,21 @@ extern pid_t read_pid (const char *pidfile); * table (using /proc) to determine if the process already exists. If * so 1 is returned, otherwise 0. */ -extern pid_t check_pid (const char *pidfile); +extern pid_t check_pid(const char *pidfile); /* write_pid * * Writes the pid to the specified file. If that fails 0 is * returned, otherwise the pid. */ -extern pid_t write_pid (const char *pidfile); +extern pid_t write_pid(const char *pidfile); /* remove_pid * * Remove the the specified file. The result from unlink(2) * is returned */ -extern int remove_pid (const char *pidfile); +extern int remove_pid(const char *pidfile); #endif #endif diff --git a/src/process.c b/src/process.c index 9969146..4c85ce2 100644 --- a/src/process.c +++ b/src/process.c @@ -66,6 +66,7 @@ bool install_service(void) { SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"}; manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if(!manager) { logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError())); return false; @@ -83,25 +84,29 @@ bool install_service(void) { for(argp = g_argv + 1; *argp; argp++) { space = strchr(*argp, ' '); strncat(command, " ", sizeof(command) - strlen(command)); - - if(space) + + if(space) { strncat(command, "\"", sizeof(command) - strlen(command)); - + } + strncat(command, *argp, sizeof(command) - strlen(command)); - if(space) + if(space) { strncat(command, "\"", sizeof(command) - strlen(command)); + } } service = CreateService(manager, identname, identname, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - command, NULL, NULL, NULL, NULL, NULL); - + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + command, NULL, NULL, NULL, NULL, NULL); + if(!service) { DWORD lasterror = GetLastError(); logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror)); - if(lasterror != ERROR_SERVICE_EXISTS) + + if(lasterror != ERROR_SERVICE_EXISTS) { return false; + } } if(service) { @@ -111,16 +116,18 @@ bool install_service(void) { service = OpenService(manager, identname, SERVICE_ALL_ACCESS); } - if(!StartService(service, 0, NULL)) + if(!StartService(service, 0, NULL)) { logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError())); - else + } else { logger(LOG_INFO, "%s service started", identname); + } return true; } bool remove_service(void) { manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if(!manager) { logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError())); return false; @@ -133,10 +140,11 @@ bool remove_service(void) { return false; } - if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) + if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) { logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError())); - else + } else { logger(LOG_INFO, "%s service stopped", identname); + } if(!DeleteService(service)) { logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError())); @@ -150,61 +158,64 @@ bool remove_service(void) { DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) { switch(request) { - case SERVICE_CONTROL_INTERROGATE: - SetServiceStatus(statushandle, &status); - return NO_ERROR; - case SERVICE_CONTROL_STOP: - logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP"); - break; - case SERVICE_CONTROL_SHUTDOWN: - logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN"); - break; - default: - logger(LOG_WARNING, "Got unexpected request %d", (int)request); - return ERROR_CALL_NOT_IMPLEMENTED; + case SERVICE_CONTROL_INTERROGATE: + SetServiceStatus(statushandle, &status); + return NO_ERROR; + + case SERVICE_CONTROL_STOP: + logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP"); + break; + + case SERVICE_CONTROL_SHUTDOWN: + logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN"); + break; + + default: + logger(LOG_WARNING, "Got unexpected request %d", (int)request); + return ERROR_CALL_NOT_IMPLEMENTED; } if(running) { running = false; - status.dwWaitHint = 30000; - status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwWaitHint = 30000; + status.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(statushandle, &status); return NO_ERROR; } else { - status.dwWaitHint = 0; - status.dwCurrentState = SERVICE_STOPPED; + status.dwWaitHint = 0; + status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(statushandle, &status); exit(1); } } -VOID WINAPI run_service(DWORD argc, LPTSTR* argv) { +VOID WINAPI run_service(DWORD argc, LPTSTR *argv) { extern int main2(int argc, char **argv); - status.dwServiceType = SERVICE_WIN32; + status.dwServiceType = SERVICE_WIN32; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - status.dwWin32ExitCode = 0; - status.dwServiceSpecificExitCode = 0; - status.dwCheckPoint = 0; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; - statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); + statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); - if (!statushandle) { + if(!statushandle) { logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError())); } else { - status.dwWaitHint = 30000; - status.dwCurrentState = SERVICE_START_PENDING; + status.dwWaitHint = 30000; + status.dwCurrentState = SERVICE_START_PENDING; SetServiceStatus(statushandle, &status); - status.dwWaitHint = 0; + status.dwWaitHint = 0; status.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(statushandle, &status); main2(argc, argv); status.dwWaitHint = 0; - status.dwCurrentState = SERVICE_STOPPED; + status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(statushandle, &status); } @@ -220,9 +231,9 @@ bool init_service(void) { if(!StartServiceCtrlDispatcher(services)) { if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { return false; - } - else + } else { logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError())); + } } return true; @@ -241,9 +252,11 @@ static bool write_pidfile(void) { if(pid) { if(netname) fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n", - netname, (long)pid); - else + netname, (long)pid); + else { fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid); + } + return false; } @@ -269,21 +282,24 @@ bool kill_other(int signal) { if(!pid) { if(netname) fprintf(stderr, "No other tincd is running for net `%s'.\n", - netname); - else + netname); + else { fprintf(stderr, "No other tincd is running.\n"); + } + return false; } - errno = 0; /* No error, sometimes errno is only changed on error */ + errno = 0; /* No error, sometimes errno is only changed on error */ /* ESRCH is returned when no process with that pid is found */ if(kill(pid, signal) && errno == ESRCH) { if(netname) fprintf(stderr, "The tincd for net `%s' is no longer running. ", - netname); - else + netname); + else { fprintf(stderr, "The tincd is no longer running. "); + } fprintf(stderr, "Removing stale lock file.\n"); remove_pid(pidfilename); @@ -304,8 +320,10 @@ bool detach(void) { /* First check if we can open a fresh new pidfile */ #ifndef HAVE_MINGW - if(!write_pidfile()) + + if(!write_pidfile()) { return false; + } /* If we succeeded in doing that, detach */ @@ -314,9 +332,10 @@ bool detach(void) { if(do_detach) { #ifndef HAVE_MINGW + if(daemon(0, 0)) { fprintf(stderr, "Couldn't detach from terminal: %s", - strerror(errno)); + strerror(errno)); return false; } @@ -326,16 +345,20 @@ bool detach(void) { fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno)); return false; } + #else - if(!statushandle) + + if(!statushandle) { exit(install_service()); + } + #endif } - openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR)); + openlogger(identname, use_logfile ? LOGMODE_FILE : (do_detach ? LOGMODE_SYSLOG : LOGMODE_STDERR)); logger(LOG_NOTICE, "tincd %s starting, debug level %d", - VERSION, debug_level); + VERSION, debug_level); return true; } @@ -343,8 +366,11 @@ bool detach(void) { #ifdef HAVE_PUTENV void unputenv(char *p) { char *e = strchr(p, '='); - if(!e) + + if(!e) { return; + } + int len = e - p; #ifndef HAVE_UNSETENV #ifdef HAVE_MINGW @@ -361,13 +387,16 @@ void unputenv(char *p) { // We must keep what we putenv() around in memory. // To do this without memory leaks, keep things in a list and reuse if possible. static list_t list = {}; + for(list_node_t *node = list.head; node; node = node->next) { char *data = node->data; + if(!strcmp(data, var)) { putenv(data); return; } } + char *data = xstrdup(var); list_insert_tail(&list, data); putenv(data); @@ -389,13 +418,18 @@ bool execute_script(const char *name, char **envp) { #ifndef HAVE_MINGW len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name); #else - if(cfg_interpreter) + + if(cfg_interpreter) { len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name); - else + } else { len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name); + } + #endif - if(len < 0) + + if(len < 0) { return false; + } scriptname[len - 1] = '\0'; @@ -411,16 +445,19 @@ bool execute_script(const char *name, char **envp) { free(scriptname); len = xasprintf(&scriptname, "%s \"%s/%s\"", interpreter, confbase, name); free(interpreter); - if(len < 0) + + if(len < 0) { return false; + } } ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name); /* Set environment */ - - for(i = 0; envp[i]; i++) + + for(i = 0; envp[i]; i++) { putenv(envp[i]); + } scriptname[len - 1] = '\"'; status = system(scriptname); @@ -429,30 +466,34 @@ bool execute_script(const char *name, char **envp) { /* Unset environment */ - for(i = 0; envp[i]; i++) + for(i = 0; envp[i]; i++) { unputenv(envp[i]); + } if(status != -1) { #ifdef WEXITSTATUS - if(WIFEXITED(status)) { /* Child exited by itself */ + + if(WIFEXITED(status)) { /* Child exited by itself */ if(WEXITSTATUS(status)) { logger(LOG_ERR, "Script %s exited with non-zero status %d", - name, WEXITSTATUS(status)); + name, WEXITSTATUS(status)); return false; } - } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */ + } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */ logger(LOG_ERR, "Script %s was killed by signal %d (%s)", - name, WTERMSIG(status), strsignal(WTERMSIG(status))); + name, WTERMSIG(status), strsignal(WTERMSIG(status))); return false; - } else { /* Something strange happened */ + } else { /* Something strange happened */ logger(LOG_ERR, "Script %s terminated abnormally", name); return false; } + #endif } else { logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno)); return false; } + #endif return true; } @@ -465,23 +506,27 @@ bool execute_script(const char *name, char **envp) { #ifndef HAVE_MINGW static RETSIGTYPE sigterm_handler(int a) { logger(LOG_NOTICE, "Got %s signal", "TERM"); - if(running) + + if(running) { running = false; - else + } else { exit(1); + } } static RETSIGTYPE sigquit_handler(int a) { logger(LOG_NOTICE, "Got %s signal", "QUIT"); - if(running) + + if(running) { running = false; - else + } else { exit(1); + } } static RETSIGTYPE fatal_signal_square(int a) { logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a, - strsignal(a)); + strsignal(a)); exit(1); } @@ -519,13 +564,13 @@ static RETSIGTYPE sigint_handler(int a) { if(saved_debug_level != -1) { logger(LOG_NOTICE, "Reverting to old debug level (%d)", - saved_debug_level); + saved_debug_level); debug_level = saved_debug_level; saved_debug_level = -1; } else { logger(LOG_NOTICE, - "Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.", - debug_level); + "Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.", + debug_level); saved_debug_level = debug_level; debug_level = 5; } @@ -594,25 +639,30 @@ void setup_signals(void) { /* Set a default signal handler for every signal, errors will be ignored. */ for(i = 1; i < NSIG; i++) { - if(!do_detach) + if(!do_detach) { act.sa_handler = SIG_DFL; - else + } else { act.sa_handler = unexpected_signal_handler; + } + sigaction(i, &act, NULL); } /* If we didn't detach, allow coredumps */ - if(!do_detach) + if(!do_detach) { sighandlers[3].handler = SIG_DFL; + } /* Then, for each known signal that we want to catch, assign a handler to the signal, with error checking this time. */ for(i = 0; sighandlers[i].signal; i++) { act.sa_handler = sighandlers[i].handler; + if(sigaction(sighandlers[i].signal, &act, NULL) < 0) fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n", - sighandlers[i].signal, strsignal(sighandlers[i].signal), - strerror(errno)); + sighandlers[i].signal, strsignal(sighandlers[i].signal), + strerror(errno)); } + #endif } diff --git a/src/protocol.c b/src/protocol.c index 3c96683..144def2 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -34,30 +34,31 @@ bool strictsubnets = false; /* Jumptable for the request handlers */ static bool (*request_handlers[])(connection_t *) = { - id_h, metakey_h, challenge_h, chal_reply_h, ack_h, - status_h, error_h, termreq_h, - ping_h, pong_h, - add_subnet_h, del_subnet_h, - add_edge_h, del_edge_h, - key_changed_h, req_key_h, ans_key_h, tcppacket_h, + id_h, metakey_h, challenge_h, chal_reply_h, ack_h, + status_h, error_h, termreq_h, + ping_h, pong_h, + add_subnet_h, del_subnet_h, + add_edge_h, del_edge_h, + key_changed_h, req_key_h, ans_key_h, tcppacket_h, }; /* Request names */ static char (*request_name[]) = { - "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK", - "STATUS", "ERROR", "TERMREQ", - "PING", "PONG", - "ADD_SUBNET", "DEL_SUBNET", - "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", + "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK", + "STATUS", "ERROR", "TERMREQ", + "PING", "PONG", + "ADD_SUBNET", "DEL_SUBNET", + "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", }; static avl_tree_t *past_request_tree; bool check_id(const char *id) { for(; *id; id++) - if(!isalnum(*id) && *id != '_') + if(!isalnum(*id) && *id != '_') { return false; + } return true; } @@ -81,18 +82,18 @@ bool send_request(connection_t *c, const char *format, ...) { if(len < 0 || len > sizeof(buffer) - 1) { logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)", - c->name, c->hostname); + c->name, c->hostname); return false; } ifdebug(PROTOCOL) { sscanf(buffer, "%d", &request); ifdebug(META) - logger(LOG_DEBUG, "Sending %s to %s (%s): %s", - request_name[request], c->name, c->hostname, buffer); + logger(LOG_DEBUG, "Sending %s to %s (%s): %s", + request_name[request], c->name, c->hostname, buffer); else logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request], - c->name, c->hostname); + c->name, c->hostname); } buffer[len++] = '\n'; @@ -100,8 +101,9 @@ bool send_request(connection_t *c, const char *format, ...) { if(c == everyone) { broadcast_meta(NULL, buffer, len); return true; - } else + } else { return send_meta(c, buffer, len); + } } void forward_request(connection_t *from) { @@ -110,12 +112,12 @@ void forward_request(connection_t *from) { ifdebug(PROTOCOL) { sscanf(from->buffer, "%d", &request); ifdebug(META) - logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s", - request_name[request], from->name, from->hostname, - from->buffer); + logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s", + request_name[request], from->name, from->hostname, + from->buffer); else logger(LOG_DEBUG, "Forwarding %s from %s (%s)", - request_name[request], from->name, from->hostname); + request_name[request], from->name, from->hostname); } from->buffer[from->reqlen - 1] = '\n'; @@ -129,28 +131,28 @@ bool receive_request(connection_t *c) { if(sscanf(c->buffer, "%d", &request) == 1) { if((request < 0) || (request >= LAST) || !request_handlers[request]) { ifdebug(META) - logger(LOG_DEBUG, "Unknown request from %s (%s): %s", - c->name, c->hostname, c->buffer); + logger(LOG_DEBUG, "Unknown request from %s (%s): %s", + c->name, c->hostname, c->buffer); else logger(LOG_ERR, "Unknown request from %s (%s)", - c->name, c->hostname); + c->name, c->hostname); return false; } else { ifdebug(PROTOCOL) { ifdebug(META) - logger(LOG_DEBUG, "Got %s from %s (%s): %s", - request_name[request], c->name, c->hostname, - c->buffer); + logger(LOG_DEBUG, "Got %s from %s (%s): %s", + request_name[request], c->name, c->hostname, + c->buffer); else logger(LOG_DEBUG, "Got %s from %s (%s)", - request_name[request], c->name, c->hostname); + request_name[request], c->name, c->hostname); } } if((c->allow_request != ALL) && (c->allow_request != request)) { logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name, - c->hostname); + c->hostname); return false; } @@ -158,12 +160,12 @@ bool receive_request(connection_t *c) { /* Something went wrong. Probably scriptkiddies. Terminate. */ logger(LOG_ERR, "Error while processing %s from %s (%s)", - request_name[request], c->name, c->hostname); + request_name[request], c->name, c->hostname); return false; } } else { logger(LOG_ERR, "Bogus data received from %s (%s)", - c->name, c->hostname); + c->name, c->hostname); return false; } @@ -175,8 +177,9 @@ static int past_request_compare(const past_request_t *a, const past_request_t *b } static void free_past_request(past_request_t *r) { - if(r->request) + if(r->request) { free(r->request); + } free(r); } @@ -215,13 +218,14 @@ void age_past_requests(void) { next = node->next; p = node->data; - if(p->firstseen + pinginterval <= now) + if(p->firstseen + pinginterval <= now) { avl_delete_node(past_request_tree, node), deleted++; - else + } else { left++; + } } if(left || deleted) ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d", - deleted, left); + deleted, left); } diff --git a/src/protocol.h b/src/protocol.h index 5ddb68c..0bacd7b 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -37,7 +37,7 @@ typedef enum request_t { PROXY = -2, - ALL = -1, /* Guardian for allow_request */ + ALL = -1, /* Guardian for allow_request */ ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK, STATUS, ERROR, TERMREQ, PING, PONG, @@ -45,7 +45,7 @@ typedef enum request_t { ADD_EDGE, DEL_EDGE, KEY_CHANGED, REQ_KEY, ANS_KEY, PACKET, - LAST /* Guardian for the highest request number */ + LAST /* Guardian for the highest request number */ } request_t; typedef struct past_request_t { @@ -71,7 +71,7 @@ extern bool strictsubnets; /* Basic functions */ -extern bool send_request(struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 2, 3))); +extern bool send_request(struct connection_t *, const char *, ...) __attribute__((__format__(printf, 2, 3))); extern void forward_request(struct connection_t *); extern bool receive_request(struct connection_t *); extern bool check_id(const char *); @@ -89,7 +89,7 @@ extern bool send_challenge(struct connection_t *); extern bool send_chal_reply(struct connection_t *); extern bool send_ack(struct connection_t *); extern bool send_status(struct connection_t *, int, const char *); -extern bool send_error(struct connection_t *, int,const char *); +extern bool send_error(struct connection_t *, int, const char *); extern bool send_termreq(struct connection_t *); extern bool send_ping(struct connection_t *); extern bool send_pong(struct connection_t *); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 8288847..0d21be0 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -41,11 +41,12 @@ #include "xalloc.h" bool send_id(connection_t *c) { - if(proxytype && c->outgoing && !c->status.proxy_passed) + if(proxytype && c->outgoing && !c->status.proxy_passed) { return send_proxyrequest(c); + } return send_request(c, "%d %s %d", ID, myself->connection->name, - myself->connection->protocol_version); + myself->connection->protocol_version); } bool id_h(connection_t *c) { @@ -53,7 +54,7 @@ bool id_h(connection_t *c) { if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name, - c->hostname); + c->hostname); return false; } @@ -61,7 +62,7 @@ bool id_h(connection_t *c) { if(!check_id(name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name, - c->hostname, "invalid name"); + c->hostname, "invalid name"); return false; } @@ -70,12 +71,14 @@ bool id_h(connection_t *c) { if(c->outgoing) { if(strcmp(c->name, name)) { logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name, - c->name); + c->name); return false; } } else { - if(c->name) + if(c->name) { free(c->name); + } + c->name = xstrdup(name); } @@ -83,13 +86,15 @@ bool id_h(connection_t *c) { if(c->protocol_version != myself->connection->protocol_version) { logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d", - c->name, c->hostname, c->protocol_version); + c->name, c->hostname, c->protocol_version); return false; } if(bypass_security) { - if(!c->config_tree) + if(!c->config_tree) { init_configuration(&c->config_tree); + } + c->allow_request = ACK; return send_ack(c); } @@ -99,7 +104,7 @@ bool id_h(connection_t *c) { if(!read_connection_config(c)) { logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname, - c->name); + c->name); return false; } } @@ -136,18 +141,20 @@ bool send_metakey(connection_t *c) { /* Allocate buffers for the meta key */ char buffer[2 * len + 1]; - + c->outkey = xrealloc(c->outkey, len); if(!c->outctx) { c->outctx = EVP_CIPHER_CTX_new(); - if(!c->outctx) + + if(!c->outctx) { abort(); + } } /* Copy random data to the buffer */ - if (1 != RAND_bytes((unsigned char *)c->outkey, len)) { + if(1 != RAND_bytes((unsigned char *)c->outkey, len)) { int err = ERR_get_error(); logger(LOG_ERR, "Failed to generate meta key (%s)", ERR_error_string(err, NULL)); return false; @@ -170,7 +177,7 @@ bool send_metakey(connection_t *c) { bin2hex(c->outkey, buffer, len); buffer[len * 2] = '\0'; logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s", - buffer); + buffer); } /* Encrypt the random data @@ -182,7 +189,7 @@ bool send_metakey(connection_t *c) { if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) { logger(LOG_ERR, "Error during encryption of meta key for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -194,19 +201,19 @@ bool send_metakey(connection_t *c) { /* Send the meta key */ x = send_request(c, "%d %d %d %d %d %s", METAKEY, - c->outcipher ? EVP_CIPHER_nid(c->outcipher) : 0, - c->outdigest ? EVP_MD_type(c->outdigest) : 0, c->outmaclength, - c->outcompression, buffer); + c->outcipher ? EVP_CIPHER_nid(c->outcipher) : 0, + c->outdigest ? EVP_MD_type(c->outdigest) : 0, c->outmaclength, + c->outcompression, buffer); /* Further outgoing requests are encrypted with the key we just generated */ if(c->outcipher) { if(!EVP_EncryptInit(c->outctx, c->outcipher, - (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher), - (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher) - - EVP_CIPHER_iv_length(c->outcipher))) { + (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher), + (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher) - + EVP_CIPHER_iv_length(c->outcipher))) { logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -224,7 +231,7 @@ bool metakey_h(connection_t *c) { if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) { logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, - c->hostname); + c->hostname); return false; } @@ -243,8 +250,10 @@ bool metakey_h(connection_t *c) { if(!c->inctx) { c->inctx = EVP_CIPHER_CTX_new(); - if(!c->inctx) + + if(!c->inctx) { abort(); + } } /* Convert the challenge from hexadecimal back to binary */ @@ -256,9 +265,9 @@ bool metakey_h(connection_t *c) { /* Decrypt the meta key */ - if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ + if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -274,18 +283,18 @@ bool metakey_h(connection_t *c) { if(cipher) { c->incipher = EVP_get_cipherbynid(cipher); - + if(!c->incipher) { logger(LOG_ERR, "%s (%s) uses unknown cipher!", c->name, c->hostname); return false; } if(!EVP_DecryptInit(c->inctx, c->incipher, - (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher), - (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher) - - EVP_CIPHER_iv_length(c->incipher))) { + (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher), + (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher) - + EVP_CIPHER_iv_length(c->incipher))) { logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -333,7 +342,7 @@ bool send_challenge(connection_t *c) { /* Copy random data to the buffer */ - if (1 != RAND_bytes((unsigned char *)c->hischallenge, len)) { + if(1 != RAND_bytes((unsigned char *)c->hischallenge, len)) { int err = ERR_get_error(); logger(LOG_ERR, "Failed to generate challenge (%s)", ERR_error_string(err, NULL)); return false; // Do not send predictable challenges, let connection attempt fail. @@ -355,7 +364,7 @@ bool challenge_h(connection_t *c) { if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) { logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, - c->hostname); + c->hostname); return false; } @@ -365,7 +374,7 @@ bool challenge_h(connection_t *c) { if(strlen(buffer) != len * 2) { logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge length"); + c->hostname, "wrong challenge length"); return false; } @@ -394,15 +403,17 @@ bool send_chal_reply(connection_t *c) { /* Calculate the hash from the challenge we received */ ctx = EVP_MD_CTX_create(); - if(!ctx) + + if(!ctx) { abort(); + } if(!EVP_DigestInit(ctx, c->indigest) - || !EVP_DigestUpdate(ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)) - || !EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) { + || !EVP_DigestUpdate(ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)) + || !EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) { EVP_MD_CTX_destroy(ctx); logger(LOG_ERR, "Error during calculation of response for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -425,7 +436,7 @@ bool chal_reply_h(connection_t *c) { if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) { logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name, - c->hostname); + c->hostname); return false; } @@ -433,7 +444,7 @@ bool chal_reply_h(connection_t *c) { if(strlen(hishash) != EVP_MD_size(c->outdigest) * 2) { logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge reply length"); + c->hostname, "wrong challenge reply length"); return false; } @@ -447,15 +458,17 @@ bool chal_reply_h(connection_t *c) { /* Calculate the hash from the challenge we sent */ ctx = EVP_MD_CTX_create(); - if(!ctx) + + if(!ctx) { abort(); + } if(!EVP_DigestInit(ctx, c->outdigest) - || !EVP_DigestUpdate(ctx, c->hischallenge, RSA_size(c->rsa_key)) - || !EVP_DigestFinal(ctx, (unsigned char *)myhash, NULL)) { + || !EVP_DigestUpdate(ctx, c->hischallenge, RSA_size(c->rsa_key)) + || !EVP_DigestFinal(ctx, (unsigned char *)myhash, NULL)) { EVP_MD_CTX_destroy(ctx); logger(LOG_ERR, "Error during calculation of response from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } @@ -465,7 +478,7 @@ bool chal_reply_h(connection_t *c) { if(memcmp(hishash, myhash, EVP_MD_size(c->outdigest))) { logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge reply"); + c->hostname, "wrong challenge reply"); ifdebug(SCARY_THINGS) { bin2hex(myhash, hishash, SHA_DIGEST_LENGTH); @@ -499,19 +512,24 @@ bool send_ack(connection_t *c) { /* Check some options */ - if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT) + if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT) { c->options |= OPTION_INDIRECT; + } - if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY) + if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY) { c->options |= OPTION_TCPONLY | OPTION_INDIRECT; + } - if(myself->options & OPTION_PMTU_DISCOVERY) + if(myself->options & OPTION_PMTU_DISCOVERY) { c->options |= OPTION_PMTU_DISCOVERY; + } choice = myself->options & OPTION_CLAMP_MSS; get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice); - if(choice) + + if(choice) { c->options |= OPTION_CLAMP_MSS; + } get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight); @@ -559,7 +577,7 @@ bool ack_h(connection_t *c) { if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, - c->hostname); + c->hostname); return false; } @@ -575,7 +593,7 @@ bool ack_h(connection_t *c) { if(n->connection) { /* Oh dear, we already have a connection to this node. */ ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", - n->name, n->hostname); + n->name, n->hostname); terminate_connection(n->connection, false); /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */ graph(); @@ -584,23 +602,28 @@ bool ack_h(connection_t *c) { n->connection = c; c->node = n; + if(!(c->options & options & OPTION_PMTU_DISCOVERY)) { c->options &= ~OPTION_PMTU_DISCOVERY; options &= ~OPTION_PMTU_DISCOVERY; } + c->options |= options; - if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu) + if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu) { n->mtu = mtu; + } - if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu) + if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu) { n->mtu = mtu; + } if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) { - if(choice) + if(choice) { c->options |= OPTION_CLAMP_MSS; - else + } else { c->options &= ~OPTION_CLAMP_MSS; + } } /* Activate this connection */ @@ -609,7 +632,7 @@ bool ack_h(connection_t *c) { c->status.active = true; ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name, - c->hostname); + c->hostname); /* Send him everything we know */ @@ -630,10 +653,11 @@ bool ack_h(connection_t *c) { /* Notify everyone of the new edge */ - if(tunnelserver) + if(tunnelserver) { send_add_edge(c, c->edge); - else + } else { send_add_edge(everyone, c->edge); + } /* Run MST and SSSP algorithms */ diff --git a/src/protocol_edge.c b/src/protocol_edge.c index f58fe1a..be48e0d 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -42,8 +42,8 @@ bool send_add_edge(connection_t *c, const edge_t *e) { sockaddr2str(&e->address, &address, &port); x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(), - e->from->name, e->to->name, address, port, - e->options, e->weight); + e->from->name, e->to->name, address, port, + e->options, e->weight); free(address); free(port); @@ -62,9 +62,9 @@ bool add_edge_h(connection_t *c) { int weight; if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", - from_name, to_name, to_address, to_port, &options, &weight) != 6) { + from_name, to_name, to_address, to_port, &options, &weight) != 6) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, - c->hostname); + c->hostname); return false; } @@ -72,12 +72,13 @@ bool add_edge_h(connection_t *c) { if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, - c->hostname, "invalid name"); + c->hostname, "invalid name"); return false; } - if(seen_request(c->buffer)) + if(seen_request(c->buffer)) { return true; + } /* Lookup nodes */ @@ -85,12 +86,12 @@ bool add_edge_h(connection_t *c) { to = lookup_node(to_name); if(tunnelserver && - from != myself && from != c->node && - to != myself && to != c->node) { + from != myself && from != c->node && + to != myself && to != c->node) { /* ignore indirect edge registrations for tunnelserver */ ifdebug(PROTOCOL) logger(LOG_WARNING, - "Ignoring indirect %s from %s (%s)", - "ADD_EDGE", c->name, c->hostname); + "Ignoring indirect %s from %s (%s)", + "ADD_EDGE", c->name, c->hostname); return true; } @@ -119,17 +120,19 @@ bool add_edge_h(connection_t *c) { if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { if(from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", - "ADD_EDGE", c->name, c->hostname); + "ADD_EDGE", c->name, c->hostname); send_add_edge(c, e); return true; } else { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry", - "ADD_EDGE", c->name, c->hostname); + "ADD_EDGE", c->name, c->hostname); e->options = options; + if(sockaddrcmp(&e->address, &address)) { sockaddrfree(&e->address); e->address = address; } + if(e->weight != weight) { avl_node_t *node = avl_unlink(edge_weight_tree, e); e->weight = weight; @@ -138,11 +141,12 @@ bool add_edge_h(connection_t *c) { goto done; } - } else + } else { return true; + } } else if(from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist", - "ADD_EDGE", c->name, c->hostname); + "ADD_EDGE", c->name, c->hostname); contradicting_add_edge++; e = new_edge(); e->from = from; @@ -163,8 +167,9 @@ bool add_edge_h(connection_t *c) { done: /* Tell the rest about the new edge */ - if(!tunnelserver) + if(!tunnelserver) { forward_request(c); + } /* Run MST before or after we tell the rest? */ @@ -175,7 +180,7 @@ done: bool send_del_edge(connection_t *c, const edge_t *e) { return send_request(c, "%d %x %s %s", DEL_EDGE, rand(), - e->from->name, e->to->name); + e->from->name, e->to->name); } bool del_edge_h(connection_t *c) { @@ -186,7 +191,7 @@ bool del_edge_h(connection_t *c) { if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name, - c->hostname); + c->hostname); return false; } @@ -194,12 +199,13 @@ bool del_edge_h(connection_t *c) { if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, - c->hostname, "invalid name"); + c->hostname, "invalid name"); return false; } - if(seen_request(c->buffer)) + if(seen_request(c->buffer)) { return true; + } /* Lookup nodes */ @@ -207,24 +213,24 @@ bool del_edge_h(connection_t *c) { to = lookup_node(to_name); if(tunnelserver && - from != myself && from != c->node && - to != myself && to != c->node) { + from != myself && from != c->node && + to != myself && to != c->node) { /* ignore indirect edge registrations for tunnelserver */ ifdebug(PROTOCOL) logger(LOG_WARNING, - "Ignoring indirect %s from %s (%s)", - "DEL_EDGE", c->name, c->hostname); + "Ignoring indirect %s from %s (%s)", + "DEL_EDGE", c->name, c->hostname); return true; } if(!from) { ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", - "DEL_EDGE", c->name, c->hostname); + "DEL_EDGE", c->name, c->hostname); return true; } if(!to) { ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", - "DEL_EDGE", c->name, c->hostname); + "DEL_EDGE", c->name, c->hostname); return true; } @@ -234,22 +240,23 @@ bool del_edge_h(connection_t *c) { if(!e) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree", - "DEL_EDGE", c->name, c->hostname); + "DEL_EDGE", c->name, c->hostname); return true; } if(e->from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", - "DEL_EDGE", c->name, c->hostname); + "DEL_EDGE", c->name, c->hostname); contradicting_del_edge++; - send_add_edge(c, e); /* Send back a correction */ + send_add_edge(c, e); /* Send back a correction */ return true; } /* Tell the rest about the deleted edge */ - if(!tunnelserver) + if(!tunnelserver) { forward_request(c); + } /* Delete the edge */ @@ -263,9 +270,12 @@ bool del_edge_h(connection_t *c) { if(!to->status.reachable) { e = lookup_edge(to, myself); + if(e) { - if(!tunnelserver) + if(!tunnelserver) { send_del_edge(everyone, e); + } + edge_del(e); } } diff --git a/src/protocol_key.c b/src/protocol_key.c index 5f71d1c..ee292b6 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -46,8 +46,10 @@ void send_key_changed(void) { for(node = connection_tree->head; node; node = node->next) { c = node->data; - if(c->status.active && c->node && c->node->status.reachable) + + if(c->status.active && c->node && c->node->status.reachable) { send_ans_key(c->node); + } } } @@ -57,7 +59,7 @@ bool key_changed_h(connection_t *c) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) { logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED", - c->name, c->hostname); + c->name, c->hostname); return false; } @@ -66,14 +68,15 @@ bool key_changed_h(connection_t *c) { return false; } - if(seen_request(c->buffer)) + if(seen_request(c->buffer)) { return true; + } n = lookup_node(name); if(!n) { logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist", - "KEY_CHANGED", c->name, c->hostname, name); + "KEY_CHANGED", c->name, c->hostname, name); return true; } @@ -82,8 +85,9 @@ bool key_changed_h(connection_t *c) { /* Tell the others */ - if(!tunnelserver) + if(!tunnelserver) { forward_request(c); + } return true; } @@ -99,7 +103,7 @@ bool req_key_h(connection_t *c) { if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name, - c->hostname); + c->hostname); return false; } @@ -112,7 +116,7 @@ bool req_key_h(connection_t *c) { if(!from) { logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", - "REQ_KEY", c->name, c->hostname, from_name); + "REQ_KEY", c->name, c->hostname, from_name); return true; } @@ -120,22 +124,24 @@ bool req_key_h(connection_t *c) { if(!to) { logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", - "REQ_KEY", c->name, c->hostname, to_name); + "REQ_KEY", c->name, c->hostname, to_name); return true; } /* Check if this key request is for us */ - if(to == myself) { /* Yes, send our own key back */ - if (!send_ans_key(from)) + if(to == myself) { /* Yes, send our own key back */ + if(!send_ans_key(from)) { return false; + } } else { - if(tunnelserver) + if(tunnelserver) { return true; + } if(!to->status.reachable) { logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", - "REQ_KEY", c->name, c->hostname, to_name); + "REQ_KEY", c->name, c->hostname, to_name); return true; } @@ -157,19 +163,23 @@ bool send_ans_key(node_t *to) { to->inkey = xrealloc(to->inkey, to->inkeylength); // Create a new key - if (1 != RAND_bytes((unsigned char *)to->inkey, to->inkeylength)) { + if(1 != RAND_bytes((unsigned char *)to->inkey, to->inkeylength)) { int err = ERR_get_error(); logger(LOG_ERR, "Failed to generate random for key (%s)", ERR_error_string(err, NULL)); return false; // Do not send insecure keys, let connection attempt fail. } - if(to->incipher) + if(to->incipher) { EVP_DecryptInit_ex(to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + EVP_CIPHER_key_length(to->incipher)); + } // Reset sequence number and late packet window mykeyused = true; to->received_seqno = 0; - if(replaywin) memset(to->late, 0, replaywin); + + if(replaywin) { + memset(to->late, 0, replaywin); + } // Convert to hexadecimal and send char key[2 * to->inkeylength + 1]; @@ -177,10 +187,10 @@ bool send_ans_key(node_t *to) { key[to->inkeylength * 2] = '\0'; return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY, - myself->name, to->name, key, - to->incipher ? EVP_CIPHER_nid(to->incipher) : 0, - to->indigest ? EVP_MD_type(to->indigest) : 0, to->inmaclength, - to->incompression); + myself->name, to->name, key, + to->incipher ? EVP_CIPHER_nid(to->incipher) : 0, + to->indigest ? EVP_MD_type(to->indigest) : 0, to->inmaclength, + to->incompression); } bool ans_key_h(connection_t *c) { @@ -193,10 +203,10 @@ bool ans_key_h(connection_t *c) { node_t *from, *to; if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, - from_name, to_name, key, &cipher, &digest, &maclength, - &compression, address, port) < 7) { + from_name, to_name, key, &cipher, &digest, &maclength, + &compression, address, port) < 7) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, - c->hostname); + c->hostname); return false; } @@ -209,7 +219,7 @@ bool ans_key_h(connection_t *c) { if(!from) { logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", - "ANS_KEY", c->name, c->hostname, from_name); + "ANS_KEY", c->name, c->hostname, from_name); return true; } @@ -217,19 +227,20 @@ bool ans_key_h(connection_t *c) { if(!to) { logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", - "ANS_KEY", c->name, c->hostname, to_name); + "ANS_KEY", c->name, c->hostname, to_name); return true; } /* Forward it if necessary */ if(to != myself) { - if(tunnelserver) + if(tunnelserver) { return true; + } if(!to->status.reachable) { logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", - "ANS_KEY", c->name, c->hostname, to_name); + "ANS_KEY", c->name, c->hostname, to_name); return true; } @@ -252,6 +263,7 @@ bool ans_key_h(connection_t *c) { /* Update our copy of the origin's packet key */ from->outkey = xrealloc(from->outkey, strlen(key) / 2); from->outkeylength = strlen(key) / 2; + if(!hex2bin(key, from->outkey, from->outkeylength)) { logger(LOG_ERR, "Got bad %s from %s(%s): %s", "ANS_KEY", from->name, from->hostname, "invalid key"); return true; @@ -264,13 +276,13 @@ bool ans_key_h(connection_t *c) { if(!from->outcipher) { logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, - from->hostname); + from->hostname); return true; } if(from->outkeylength != EVP_CIPHER_key_length(from->outcipher) + EVP_CIPHER_iv_length(from->outcipher)) { logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, - from->hostname); + from->hostname); return true; } } else { @@ -284,13 +296,13 @@ bool ans_key_h(connection_t *c) { if(!from->outdigest) { logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, - from->hostname); + from->hostname); return true; } if(from->outmaclength > EVP_MD_size(from->outdigest) || from->outmaclength < 0) { logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", - from->name, from->hostname); + from->name, from->hostname); return true; } } else { @@ -301,13 +313,13 @@ bool ans_key_h(connection_t *c) { logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname); return true; } - + from->outcompression = compression; if(from->outcipher) if(!EVP_EncryptInit_ex(from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + EVP_CIPHER_key_length(from->outcipher))) { logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s", - from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL)); + from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL)); return true; } @@ -320,8 +332,9 @@ bool ans_key_h(connection_t *c) { update_node_udp(from, &sa); } - if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent) + if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent) { send_mtu_probe(from); + } return true; } diff --git a/src/protocol_misc.c b/src/protocol_misc.c index 05afbce..c08a0d1 100644 --- a/src/protocol_misc.c +++ b/src/protocol_misc.c @@ -34,8 +34,9 @@ int maxoutbufsize = 0; /* Status and error notification routines */ bool send_status(connection_t *c, int statusno, const char *statusstring) { - if(!statusstring) + if(!statusstring) { statusstring = "Status"; + } return send_request(c, "%d %d %s", STATUS, statusno, statusstring); } @@ -46,19 +47,20 @@ bool status_h(connection_t *c) { if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "STATUS", - c->name, c->hostname); + c->name, c->hostname); return false; } ifdebug(STATUS) logger(LOG_NOTICE, "Status message from %s (%s): %d: %s", - c->name, c->hostname, statusno, statusstring); + c->name, c->hostname, statusno, statusstring); return true; } bool send_error(connection_t *c, int err, const char *errstring) { - if(!errstring) + if(!errstring) { errstring = "Error"; + } return send_request(c, "%d %d %s", ERROR, err, errstring); } @@ -69,12 +71,12 @@ bool error_h(connection_t *c) { if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ERROR", - c->name, c->hostname); + c->name, c->hostname); return false; } ifdebug(ERROR) logger(LOG_NOTICE, "Error message from %s (%s): %d: %s", - c->name, c->hostname, err, errorstring); + c->name, c->hostname, err, errorstring); terminate_connection(c, c->status.active); @@ -114,8 +116,11 @@ bool pong_h(connection_t *c) { if(c->outgoing) { c->outgoing->timeout = 0; c->outgoing->cfg = NULL; - if(c->outgoing->ai) + + if(c->outgoing->ai) { freeaddrinfo(c->outgoing->ai); + } + c->outgoing->ai = NULL; c->outgoing->aip = NULL; } @@ -127,13 +132,15 @@ bool pong_h(connection_t *c) { bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) { /* If there already is a lot of data in the outbuf buffer, discard this packet. - We use a very simple Random Early Drop algorithm. */ + We use a very simple Random Early Drop algorithm. */ - if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX) + if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand() / (float)RAND_MAX) { return true; + } - if(!send_request(c, "%d %hd", PACKET, packet->len)) + if(!send_request(c, "%d %hd", PACKET, packet->len)) { return false; + } return send_meta(c, (char *)packet->data, packet->len) && flush_meta(c); } @@ -143,7 +150,7 @@ bool tcppacket_h(connection_t *c) { if(sscanf(c->buffer, "%*d %hd", &len) != 1) { logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name, - c->hostname); + c->hostname); return false; } diff --git a/src/protocol_subnet.c b/src/protocol_subnet.c index 15ec8bf..0bdcb73 100644 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@ -35,8 +35,9 @@ bool send_add_subnet(connection_t *c, const subnet_t *subnet) { char netstr[MAXNETSTR]; - if(!net2str(netstr, sizeof(netstr), subnet)) + if(!net2str(netstr, sizeof(netstr), subnet)) { return false; + } return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr); } @@ -49,7 +50,7 @@ bool add_subnet_h(connection_t *c) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, - c->hostname); + c->hostname); return false; } @@ -57,7 +58,7 @@ bool add_subnet_h(connection_t *c) { if(!check_id(name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, - c->hostname, "invalid name"); + c->hostname, "invalid name"); return false; } @@ -65,12 +66,13 @@ bool add_subnet_h(connection_t *c) { if(!str2net(&s, subnetstr)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, - c->hostname, "invalid subnet string"); + c->hostname, "invalid subnet string"); return false; } - if(seen_request(c->buffer)) + if(seen_request(c->buffer)) { return true; + } /* Check if the owner of the new subnet is in the connection list */ @@ -79,7 +81,7 @@ bool add_subnet_h(connection_t *c) { if(tunnelserver && owner != myself && owner != c->node) { /* in case of tunnelserver, ignore indirect subnet registrations */ ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); + "ADD_SUBNET", c->name, c->hostname, subnetstr); return true; } @@ -91,14 +93,15 @@ bool add_subnet_h(connection_t *c) { /* Check if we already know this subnet */ - if(lookup_subnet(owner, &s)) + if(lookup_subnet(owner, &s)) { return true; + } /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */ if(owner == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", - "ADD_SUBNET", c->name, c->hostname); + "ADD_SUBNET", c->name, c->hostname); s.owner = myself; send_del_subnet(c, &s); return true; @@ -108,7 +111,7 @@ bool add_subnet_h(connection_t *c) { if(tunnelserver) { logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); + "ADD_SUBNET", c->name, c->hostname, subnetstr); return true; } @@ -116,7 +119,7 @@ bool add_subnet_h(connection_t *c) { if(strictsubnets) { logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); + "ADD_SUBNET", c->name, c->hostname, subnetstr); forward_request(c); return true; } @@ -126,8 +129,9 @@ bool add_subnet_h(connection_t *c) { *(new = new_subnet()) = s; subnet_add(owner, new); - if(owner->status.reachable) + if(owner->status.reachable) { subnet_update(owner, new, true); + } /* Tell the rest */ @@ -135,8 +139,9 @@ bool add_subnet_h(connection_t *c) { /* Fast handoff of roaming MAC addresses */ - if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) + if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) { old->expires = now; + } return true; } @@ -144,8 +149,9 @@ bool add_subnet_h(connection_t *c) { bool send_del_subnet(connection_t *c, const subnet_t *s) { char netstr[MAXNETSTR]; - if(!net2str(netstr, sizeof(netstr), s)) + if(!net2str(netstr, sizeof(netstr), s)) { return false; + } return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr); } @@ -158,7 +164,7 @@ bool del_subnet_h(connection_t *c) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name, - c->hostname); + c->hostname); return false; } @@ -166,7 +172,7 @@ bool del_subnet_h(connection_t *c) { if(!check_id(name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, - c->hostname, "invalid name"); + c->hostname, "invalid name"); return false; } @@ -174,12 +180,13 @@ bool del_subnet_h(connection_t *c) { if(!str2net(&s, subnetstr)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, - c->hostname, "invalid subnet string"); + c->hostname, "invalid subnet string"); return false; } - if(seen_request(c->buffer)) + if(seen_request(c->buffer)) { return true; + } /* Check if the owner of the subnet being deleted is in the connection list */ @@ -188,13 +195,13 @@ bool del_subnet_h(connection_t *c) { if(tunnelserver && owner != myself && owner != c->node) { /* in case of tunnelserver, ignore indirect subnet deletion */ ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", - "DEL_SUBNET", c->name, c->hostname, subnetstr); + "DEL_SUBNET", c->name, c->hostname, subnetstr); return true; } if(!owner) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree", - "DEL_SUBNET", c->name, c->hostname, name); + "DEL_SUBNET", c->name, c->hostname, name); return true; } @@ -206,9 +213,12 @@ bool del_subnet_h(connection_t *c) { if(!find) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree", - "DEL_SUBNET", c->name, c->hostname, name); - if(strictsubnets) + "DEL_SUBNET", c->name, c->hostname, name); + + if(strictsubnets) { forward_request(c); + } + return true; } @@ -216,24 +226,28 @@ bool del_subnet_h(connection_t *c) { if(owner == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", - "DEL_SUBNET", c->name, c->hostname); + "DEL_SUBNET", c->name, c->hostname); send_add_subnet(c, find); return true; } - if(tunnelserver) + if(tunnelserver) { return true; + } /* Tell the rest */ forward_request(c); - if(strictsubnets) + + if(strictsubnets) { return true; + } /* Finally, delete it. */ - if(owner->status.reachable) + if(owner->status.reachable) { subnet_update(owner, find, false); + } subnet_del(owner, find); diff --git a/src/proxy.c b/src/proxy.c index 75e41de..882871c 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -37,26 +37,38 @@ static void update_address_ipv4(connection_t *c, void *address, void *port) { sockaddrfree(&c->address); memset(&c->address, 0, sizeof(c->address)); c->address.sa.sa_family = AF_INET; - if(address) + + if(address) { memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t)); - if(port) + } + + if(port) { memcpy(&c->address.in.sin_port, port, sizeof(uint16_t)); + } + // OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves. - if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4)) + if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4)) { memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4); + } } static void update_address_ipv6(connection_t *c, void *address, void *port) { sockaddrfree(&c->address); memset(&c->address, 0, sizeof(c->address)); c->address.sa.sa_family = AF_INET6; - if(address) + + if(address) { memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t)); - if(port) + } + + if(port) { memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t)); + } + // OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves. - if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) { memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8); + } } bool send_proxyrequest(connection_t *c) { @@ -66,19 +78,27 @@ bool send_proxyrequest(connection_t *c) { logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!"); return false; } + case PROXY_SOCKS4A: { if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) { logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!"); return false; } + int len = 9; - if(proxyuser) + + if(proxyuser) { len += strlen(proxyuser); - if(c->address.sa.sa_family == AF_UNKNOWN) + } + + if(c->address.sa.sa_family == AF_UNKNOWN) { len += 1 + strlen(c->address.unknown.address); + } + char s4req[len]; s4req[0] = 4; s4req[1] = 1; + if(c->address.sa.sa_family == AF_INET) { memcpy(s4req + 2, &c->address.in.sin_port, 2); memcpy(s4req + 4, &c->address.in.sin_addr, 4); @@ -88,10 +108,13 @@ bool send_proxyrequest(connection_t *c) { memcpy(s4req + 4, "\0\0\0\1", 4); strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address); } - if(proxyuser) + + if(proxyuser) { strcpy(s4req + 8, proxyuser); - else + } else { s4req[8] = 0; + } + s4req[sizeof(s4req) - 1] = 0; c->allow_request = PROXY; return send_meta(c, s4req, sizeof(s4req)); @@ -99,6 +122,7 @@ bool send_proxyrequest(connection_t *c) { case PROXY_SOCKS5: { int len = 3 + 6; + if(c->address.sa.sa_family == AF_INET) { len += 4; } else if(c->address.sa.sa_family == AF_INET6) { @@ -109,12 +133,16 @@ bool send_proxyrequest(connection_t *c) { logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family); return false; } - if(proxypass) + + if(proxypass) { len += 3 + strlen(proxyuser) + strlen(proxypass); + } + char s5req[len]; int i = 0; s5req[i++] = 5; s5req[i++] = 1; + if(proxypass) { s5req[i++] = 2; s5req[i++] = 1; @@ -127,9 +155,11 @@ bool send_proxyrequest(connection_t *c) { } else { s5req[i++] = 0; } + s5req[i++] = 5; s5req[i++] = 1; s5req[i++] = 0; + if(c->address.sa.sa_family == AF_INET) { s5req[i++] = 1; memcpy(s5req + i, &c->address.in.sin_addr, 4); @@ -155,8 +185,11 @@ bool send_proxyrequest(connection_t *c) { logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy"); return false; } - if(i > len) + + if(i > len) { abort(); + } + c->allow_request = PROXY; return send_meta(c, s5req, sizeof(s5req)); } @@ -186,11 +219,14 @@ int receive_proxy_meta(connection_t *c, int start, int lenin) { switch(proxytype) { case PROXY_SOCKS4: case PROXY_SOCKS4A: - if(c->buflen < 8) + if(c->buflen < 8) { return 0; + } + if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) { - if(c->address.sa.sa_family == AF_UNKNOWN) + if(c->address.sa.sa_family == AF_UNKNOWN) { update_address_ipv4(c, c->buffer + 4, c->buffer + 2); + } ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted"); c->allow_request = ID; @@ -203,49 +239,71 @@ int receive_proxy_meta(connection_t *c, int start, int lenin) { } case PROXY_SOCKS5: - if(c->buflen < 2) + if(c->buflen < 2) { return 0; + } + if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) { logger(LOG_ERR, "Proxy authentication method rejected"); return -1; } + int offset = 2; + if(c->buffer[1] == 0x02) { - if(c->buflen < 4) + if(c->buflen < 4) { return 0; + } + if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) { logger(LOG_ERR, "Proxy username/password rejected"); return -1; } + offset += 2; } - if(c->buflen - offset < 7) + + if(c->buflen - offset < 7) { return 0; + } + if(c->buffer[offset] != 0x05 || c->buffer[offset + 1] != 0x00) { logger(LOG_ERR, "Proxy request rejected"); return -1; } + int replen = offset + 6; + switch(c->buffer[offset + 3]) { - case 0x01: // IPv4 - if(c->address.sa.sa_family == AF_UNKNOWN) - update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8); - replen += 4; - break; - case 0x03: // Hostname - if(c->address.sa.sa_family == AF_UNKNOWN) - update_address_ipv4(c, "\0\0\0\1", "\0\0"); - replen += ((uint8_t *)c->buffer)[offset + 4]; - break; - case 0x04: // IPv6 - if(c->address.sa.sa_family == AF_UNKNOWN) - update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20); - replen += 16; - break; - default: - logger(LOG_ERR, "Proxy reply malformed"); - return -1; + case 0x01: // IPv4 + if(c->address.sa.sa_family == AF_UNKNOWN) { + update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8); + } + + replen += 4; + break; + + case 0x03: // Hostname + if(c->address.sa.sa_family == AF_UNKNOWN) { + update_address_ipv4(c, "\0\0\0\1", "\0\0"); + } + + replen += ((uint8_t *)c->buffer)[offset + 4]; + break; + + case 0x04: // IPv6 + if(c->address.sa.sa_family == AF_UNKNOWN) { + update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20); + } + + replen += 16; + break; + + default: + logger(LOG_ERR, "Proxy reply malformed"); + return -1; } + if(c->buflen < replen) { return 0; } else { @@ -258,24 +316,31 @@ int receive_proxy_meta(connection_t *c, int start, int lenin) { case PROXY_HTTP: { char *p = memchr(c->buffer, '\n', c->buflen); - if(!p || p - c->buffer >= c->buflen) + + if(!p || p - c->buffer >= c->buflen) { return 0; + } while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) { - if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) + if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) { break; + } } - if(!p) + if(!p) { return 0; + } - if(c->buflen < 9) + if(c->buflen < 9) { return 0; + } if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) { if(!strncmp(c->buffer + 9, "200", 3)) { - if(c->address.sa.sa_family == AF_UNKNOWN) + if(c->address.sa.sa_family == AF_UNKNOWN) { update_address_ipv4(c, "\0\0\0\1", "\0\0"); + } + logger(LOG_DEBUG, "Proxy request granted"); replen = p + 1 - c->buffer; c->allow_request = ID; diff --git a/src/raw_socket_device.c b/src/raw_socket_device.c index 427fb3f..92f07c6 100644 --- a/src/raw_socket_device.c +++ b/src/raw_socket_device.c @@ -42,17 +42,19 @@ static bool setup_device(void) { struct ifreq ifr; struct sockaddr_ll sa; - if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) + if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) { iface = xstrdup("eth0"); + } - if(!get_config_string(lookup_config(config_tree, "Device"), &device)) + if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { device = xstrdup(iface); + } device_info = "raw socket"; if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { logger(LOG_ERR, "Could not open %s: %s", device_info, - strerror(errno)); + strerror(errno)); return false; } @@ -97,7 +99,7 @@ static bool read_packet(vpn_packet_t *packet) { if((lenin = read(device_fd, packet->data, MTU)) <= 0) { logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); + device, strerror(errno)); return false; } @@ -106,18 +108,18 @@ static bool read_packet(vpn_packet_t *packet) { device_total_in += packet->len; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, - device_info); + device_info); return true; } static bool write_packet(vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); if(write(device_fd, packet->data, packet->len) < 0) { logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, - strerror(errno)); + strerror(errno)); return false; } diff --git a/src/route.c b/src/route.c index ef68759..7530e42 100644 --- a/src/route.c +++ b/src/route.c @@ -2,7 +2,7 @@ route.c -- routing Copyright (C) 2000-2005 Ivo Timmermans, 2000-2017 Guus Sliepen - 2015-2016 Vittorio Gambaletta + 2015-2016 Vittorio Gambaletta This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -68,12 +68,14 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { checksum += *p++; len -= 2; } - - if(len) + + if(len) { checksum += *(uint8_t *)p; + } - while(checksum >> 16) + while(checksum >> 16) { checksum = (checksum & 0xFFFF) + (checksum >> 16); + } return ~checksum; } @@ -81,10 +83,11 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { static bool ratelimit(int frequency) { static time_t lasttime = 0; static int count = 0; - + if(lasttime == now) { - if(count >= frequency) + if(count >= frequency) { return true; + } } else { lasttime = now; count = 0; @@ -98,8 +101,9 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) { if(packet->len < length) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Got too short packet from %s (%s)", source->name, source->hostname); return false; - } else + } else { return true; + } } static void swap_mac_addresses(vpn_packet_t *packet) { @@ -114,14 +118,15 @@ static void swap_mac_addresses(vpn_packet_t *packet) { static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { struct ip ip = {0}; struct icmp icmp = {0}; - + struct in_addr ip_src; struct in_addr ip_dst; uint32_t oldlen; - if(ratelimit(3)) + if(ratelimit(3)) { return; - + } + /* Swap Ethernet source and destination addresses */ swap_mac_addresses(packet); @@ -131,45 +136,51 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ memcpy(&ip, packet->data + ether_size, ip_size); /* Remember original source and destination */ - + ip_src = ip.ip_src; ip_dst = ip.ip_dst; /* Try to reply with an IP address assigned to the local machine */ - if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) { + if(type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd != -1) { + + if(sockfd != -1) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = ip.ip_src; - if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + + if(!connect(sockfd, (const struct sockaddr *) &addr, sizeof(addr))) { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; socklen_t addrlen = sizeof(addr); - if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + + if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) { ip_dst = addr.sin_addr; } } + close(sockfd); } } oldlen = packet->len - ether_size; - if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) + if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { icmp.icmp_nextmtu = htons(packet->len - ether_size); + } - if(oldlen >= IP_MSS - ip_size - icmp_size) + if(oldlen >= IP_MSS - ip_size - icmp_size) { oldlen = IP_MSS - ip_size - icmp_size; - + } + /* Copy first part of original contents to ICMP message */ - + memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen); /* Fill in IPv4 header */ - + ip.ip_v = 4; ip.ip_hl = ip_size / 4; ip.ip_tos = 0; @@ -183,13 +194,13 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ ip.ip_dst = ip_src; ip.ip_sum = inet_checksum(&ip, ip_size, ~0); - + /* Fill in ICMP header */ - + icmp.icmp_type = type; icmp.icmp_code = code; icmp.icmp_cksum = 0; - + icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0); icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum); @@ -197,7 +208,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ memcpy(packet->data + ether_size, &ip, ip_size); memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size); - + packet->len = ether_size + ip_size + icmp_size + oldlen; send_packet(source, packet); @@ -208,18 +219,19 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { struct ip6_hdr ip6; struct icmp6_hdr icmp6 = {0}; - uint16_t checksum; + uint16_t checksum; struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* destination address */ uint32_t length; uint32_t next; } pseudo; - if(ratelimit(3)) + if(ratelimit(3)) { return; - + } + /* Swap Ethernet source and destination addresses */ swap_mac_addresses(packet); @@ -229,45 +241,51 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_ memcpy(&ip6, packet->data + ether_size, ip6_size); /* Remember original source and destination */ - + pseudo.ip6_src = ip6.ip6_dst; pseudo.ip6_dst = ip6.ip6_src; /* Try to reply with an IP address assigned to the local machine */ - if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) { + if(type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) { int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); - if (sockfd != -1) { + + if(sockfd != -1) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = ip6.ip6_src; - if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + + if(!connect(sockfd, (const struct sockaddr *) &addr, sizeof(addr))) { memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; socklen_t addrlen = sizeof(addr); - if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + + if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) { pseudo.ip6_src = addr.sin6_addr; } } + close(sockfd); } } pseudo.length = packet->len - ether_size; - if(type == ICMP6_PACKET_TOO_BIG) + if(type == ICMP6_PACKET_TOO_BIG) { icmp6.icmp6_mtu = htonl(pseudo.length); - - if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) + } + + if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) { pseudo.length = IP_MSS - ip6_size - icmp6_size; - + } + /* Copy first part of original contents to ICMP message */ - + memmove(packet->data + ether_size + ip6_size + icmp6_size, packet->data + ether_size, pseudo.length); /* Fill in IPv6 header */ - + ip6.ip6_flow = htonl(0x60000000UL); ip6.ip6_plen = htons(icmp6_size + pseudo.length); ip6.ip6_nxt = IPPROTO_ICMPV6; @@ -276,18 +294,18 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_ ip6.ip6_dst = pseudo.ip6_dst; /* Fill in ICMP header */ - + icmp6.icmp6_type = type; icmp6.icmp6_code = code; icmp6.icmp6_cksum = 0; /* Create pseudo header */ - + pseudo.length = htonl(icmp6_size + pseudo.length); pseudo.next = htonl(IPPROTO_ICMPV6); /* Generate checksum */ - + checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); checksum = inet_checksum(&icmp6, icmp6_size, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); @@ -298,9 +316,9 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_ memcpy(packet->data + ether_size, &ip6, ip6_size); memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size); - + packet->len = ether_size + ip6_size + ntohl(pseudo.length); - + send_packet(source, packet); } @@ -313,56 +331,68 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { ethlen += 4; } - switch (type) { - case ETH_P_IP: - if(!checklength(source, packet, ethlen + ip_size)) - return false; + switch(type) { + case ETH_P_IP: + if(!checklength(source, packet, ethlen + ip_size)) { + return false; + } - if(packet->data[ethlen + 8] <= 1) { - if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) - route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); - return false; + if(packet->data[ethlen + 8] <= 1) { + if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) { + route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); } - uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; - packet->data[ethlen + 8]--; - uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; + return false; + } - uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11]; - checksum += old + (~new & 0xFFFF); - while(checksum >> 16) - checksum = (checksum & 0xFFFF) + (checksum >> 16); - packet->data[ethlen + 10] = checksum >> 8; - packet->data[ethlen + 11] = checksum & 0xff; + uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; + packet->data[ethlen + 8]--; + uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; - return true; + uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11]; + checksum += old + (~new & 0xFFFF); - case ETH_P_IPV6: - if(!checklength(source, packet, ethlen + ip6_size)) - return false; + while(checksum >> 16) { + checksum = (checksum & 0xFFFF) + (checksum >> 16); + } + + packet->data[ethlen + 10] = checksum >> 8; + packet->data[ethlen + 11] = checksum & 0xff; - if(packet->data[ethlen + 7] <= 1) { - if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) - route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); - return false; + return true; + + case ETH_P_IPV6: + if(!checklength(source, packet, ethlen + ip6_size)) { + return false; + } + + if(packet->data[ethlen + 7] <= 1) { + if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) { + route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); } - packet->data[ethlen + 7]--; + return false; + } - return true; + packet->data[ethlen + 7]--; - default: - return true; + return true; + + default: + return true; } } static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) { - if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) + if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) { return; + } uint16_t mtu = source->mtu; - if(via != myself && via->mtu < mtu) + + if(via != myself && via->mtu < mtu) { mtu = via->mtu; + } /* Find TCP header */ int start = ether_size; @@ -373,53 +403,62 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac type = packet->data[16] << 8 | packet->data[17]; } - if(type == ETH_P_IP && packet->data[start + 9] == 6) + if(type == ETH_P_IP && packet->data[start + 9] == 6) { start += (packet->data[start] & 0xf) * 4; - else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) + } else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) { start += 40; - else + } else { return; + } - if(packet->len <= start + 20) + if(packet->len <= start + 20) { return; + } /* Use data offset field to calculate length of options field */ int len = ((packet->data[start + 12] >> 4) - 5) * 4; - if(packet->len < start + 20 + len) + if(packet->len < start + 20 + len) { return; + } /* Search for MSS option header */ for(int i = 0; i < len;) { - if(packet->data[start + 20 + i] == 0) + if(packet->data[start + 20 + i] == 0) { break; + } if(packet->data[start + 20 + i] == 1) { i++; continue; } - if(i > len - 2 || i > len - packet->data[start + 21 + i]) + if(i > len - 2 || i > len - packet->data[start + 21 + i]) { break; + } if(packet->data[start + 20 + i] != 2) { - if(packet->data[start + 21 + i] < 2) + if(packet->data[start + 21 + i] < 2) { break; + } + i += packet->data[start + 21 + i]; continue; } - if(packet->data[start + 21] != 4) + if(packet->data[start + 21] != 4) { break; + } /* Found it */ uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i]; uint16_t newmss = mtu - start - 20; uint32_t csum = packet->data[start + 16] << 8 | packet->data[start + 17]; - if(oldmss <= newmss) + if(oldmss <= newmss) { break; - + } + ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss); /* Update the MSS value and the checksum */ @@ -436,7 +475,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac break; } } - + static void learn_mac(mac_t *address) { subnet_t *subnet; avl_node_t *node; @@ -448,8 +487,8 @@ static void learn_mac(mac_t *address) { if(!subnet) { ifdebug(TRAFFIC) logger(LOG_INFO, "Learned new MAC address %x:%x:%x:%x:%x:%x", - address->x[0], address->x[1], address->x[2], address->x[3], - address->x[4], address->x[5]); + address->x[0], address->x[1], address->x[2], address->x[3], + address->x[4], address->x[5]); subnet = new_subnet(); subnet->type = SUBNET_MAC; @@ -463,13 +502,16 @@ static void learn_mac(mac_t *address) { for(node = connection_tree->head; node; node = node->next) { c = node->data; - if(c->status.active) + + if(c->status.active) { send_add_subnet(c, subnet); + } } } - if(subnet->expires) + if(subnet->expires) { subnet->expires = now + macexpire; + } } void age_subnets(void) { @@ -480,17 +522,22 @@ void age_subnets(void) { for(node = myself->subnet_tree->head; node; node = next) { next = node->next; s = node->data; + if(s->expires && s->expires <= now) { ifdebug(TRAFFIC) { char netstr[MAXNETSTR]; - if(net2str(netstr, sizeof(netstr), s)) + + if(net2str(netstr, sizeof(netstr), s)) { logger(LOG_INFO, "Subnet %s expired", netstr); + } } for(node2 = connection_tree->head; node2; node2 = node2->next) { c = node2->data; - if(c->status.active) + + if(c->status.active) { send_del_subnet(c, s); + } } subnet_update(myself, s, false); @@ -501,8 +548,9 @@ void age_subnets(void) { static void route_broadcast(node_t *source, vpn_packet_t *packet) { if(decrement_ttl && source != myself) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } broadcast_packet(source, packet); } @@ -515,13 +563,14 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et int len, maxlen, todo; uint8_t *offset; uint16_t ip_off, origf; - + memcpy(&ip, packet->data + ether_size, ip_size); fragment.priority = packet->priority; - if(ip.ip_hl != ip_size / 4) + if(ip.ip_hl != ip_size / 4) { return; - + } + todo = ntohs(ip.ip_len) - ip_size; if(ether_size + ip_size + todo != packet->len) { @@ -536,7 +585,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et ip_off = ntohs(ip.ip_off); origf = ip_off & ~IP_OFFMASK; ip_off &= IP_OFFMASK; - + while(todo) { len = todo > maxlen ? maxlen : todo; memcpy(fragment.data + ether_size + ip_size, offset, len); @@ -554,7 +603,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et send_packet(dest, &fragment); ip_off += len / 8; - } + } } static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { @@ -567,33 +616,37 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { if(!subnet) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d", - source->name, source->hostname, - dest.x[0], - dest.x[1], - dest.x[2], - dest.x[3]); + source->name, source->hostname, + dest.x[0], + dest.x[1], + dest.x[2], + dest.x[3]); route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); return; } - + if(subnet->owner == source) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname); return; } - if(!subnet->owner->status.reachable) + if(!subnet->owner->status.reachable) { return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNREACH); + } - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) { return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); + } if(decrement_ttl && source != myself && subnet->owner != myself) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } - if(priorityinheritance) + if(priorityinheritance) { packet->priority = packet->data[15]; + } via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; @@ -601,12 +654,14 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); return; } - - if(directonly && subnet->owner != via) + + if(directonly && subnet->owner != via) { return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); + } if(via && packet->len > MAX(via->mtu, 590) && via != myself) { ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); + if(packet->data[20] & 0x40) { packet->len = MAX(via->mtu, 590); route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); @@ -618,22 +673,24 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } static void route_ipv4(node_t *source, vpn_packet_t *packet) { - if(!checklength(source, packet, ether_size + ip_size)) + if(!checklength(source, packet, ether_size + ip_size)) { return; + } if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || ( - packet->data[30] == 255 && - packet->data[31] == 255 && - packet->data[32] == 255 && - packet->data[33] == 255))) + packet->data[30] == 255 && + packet->data[31] == 255 && + packet->data[32] == 255 && + packet->data[33] == 255))) { route_broadcast(source, packet); - else + } else { route_ipv4_unicast(source, packet); + } } static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { @@ -646,15 +703,15 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { if(!subnet) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", - source->name, source->hostname, - ntohs(dest.x[0]), - ntohs(dest.x[1]), - ntohs(dest.x[2]), - ntohs(dest.x[3]), - ntohs(dest.x[4]), - ntohs(dest.x[5]), - ntohs(dest.x[6]), - ntohs(dest.x[7])); + source->name, source->hostname, + ntohs(dest.x[0]), + ntohs(dest.x[1]), + ntohs(dest.x[2]), + ntohs(dest.x[3]), + ntohs(dest.x[4]), + ntohs(dest.x[5]), + ntohs(dest.x[6]), + ntohs(dest.x[7])); route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR); return; @@ -665,28 +722,33 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { return; } - if(!subnet->owner->status.reachable) + if(!subnet->owner->status.reachable) { return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE); + } - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) { return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); + } if(decrement_ttl && source != myself && subnet->owner != myself) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } - if(priorityinheritance) + if(priorityinheritance) { packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4); + } via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; - + if(via == source) { ifdebug(TRAFFIC) logger(LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); return; } - - if(directonly && subnet->owner != via) + + if(directonly && subnet->owner != via) { return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); + } if(via && packet->len > MAX(via->mtu, 1294) && via != myself) { ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); @@ -696,7 +758,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } @@ -711,17 +773,18 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { bool has_opt; struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* destination address */ uint32_t length; uint32_t next; } pseudo; - if(!checklength(source, packet, ether_size + ip6_size + ns_size)) + if(!checklength(source, packet, ether_size + ip6_size + ns_size)) { return; - + } + has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN; - + if(source != myself) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Got neighbor solicitation request from %s (%s) while in router mode!", source->name, source->hostname); return; @@ -731,18 +794,21 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { memcpy(&ip6, packet->data + ether_size, ip6_size); memcpy(&ns, packet->data + ether_size + ip6_size, ns_size); - if(has_opt) + + if(has_opt) { memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size); + } /* First, snatch the source address from the neighbor solicitation packet */ - if(overwrite_mac) + if(overwrite_mac) { memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); + } /* Check if this is a valid neighbor solicitation request */ if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT || - (has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) { + (has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request"); return; } @@ -751,16 +817,20 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { pseudo.ip6_src = ip6.ip6_src; pseudo.ip6_dst = ip6.ip6_dst; - if(has_opt) + + if(has_opt) { pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); - else + } else { pseudo.length = htonl(ns_size); + } + pseudo.next = htonl(IPPROTO_ICMPV6); /* Generate checksum */ checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); checksum = inet_checksum(&ns, ns_size, checksum); + if(has_opt) { checksum = inet_checksum(&opt, opt_size, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); @@ -777,57 +847,64 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { if(!subnet) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", - ntohs(((uint16_t *) &ns.nd_ns_target)[0]), - ntohs(((uint16_t *) &ns.nd_ns_target)[1]), - ntohs(((uint16_t *) &ns.nd_ns_target)[2]), - ntohs(((uint16_t *) &ns.nd_ns_target)[3]), - ntohs(((uint16_t *) &ns.nd_ns_target)[4]), - ntohs(((uint16_t *) &ns.nd_ns_target)[5]), - ntohs(((uint16_t *) &ns.nd_ns_target)[6]), - ntohs(((uint16_t *) &ns.nd_ns_target)[7])); + ntohs(((uint16_t *) &ns.nd_ns_target)[0]), + ntohs(((uint16_t *) &ns.nd_ns_target)[1]), + ntohs(((uint16_t *) &ns.nd_ns_target)[2]), + ntohs(((uint16_t *) &ns.nd_ns_target)[3]), + ntohs(((uint16_t *) &ns.nd_ns_target)[4]), + ntohs(((uint16_t *) &ns.nd_ns_target)[5]), + ntohs(((uint16_t *) &ns.nd_ns_target)[6]), + ntohs(((uint16_t *) &ns.nd_ns_target)[7])); return; } /* Check if it is for our own subnet */ - if(subnet->owner == myself) - return; /* silently ignore */ + if(subnet->owner == myself) { + return; /* silently ignore */ + } if(decrement_ttl) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } /* Create neighbor advertation reply */ - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ + packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ + ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ ip6.ip6_src = ns.nd_ns_target; - if(has_opt) - memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + if(has_opt) { + memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + } ns.nd_ns_cksum = 0; ns.nd_ns_type = ND_NEIGHBOR_ADVERT; - ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ + ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; /* Create pseudo header */ pseudo.ip6_src = ip6.ip6_src; pseudo.ip6_dst = ip6.ip6_dst; - if(has_opt) + + if(has_opt) { pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); - else + } else { pseudo.length = htonl(ns_size); + } + pseudo.next = htonl(IPPROTO_ICMPV6); /* Generate checksum */ checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); checksum = inet_checksum(&ns, ns_size, checksum); + if(has_opt) { checksum = inet_checksum(&opt, opt_size, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); @@ -839,25 +916,29 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { memcpy(packet->data + ether_size, &ip6, ip6_size); memcpy(packet->data + ether_size + ip6_size, &ns, ns_size); - if(has_opt) + + if(has_opt) { memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size); + } send_packet(source, packet); } static void route_ipv6(node_t *source, vpn_packet_t *packet) { - if(!checklength(source, packet, ether_size + ip6_size)) + if(!checklength(source, packet, ether_size + ip6_size)) { return; + } if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) { route_neighborsol(source, packet); return; } - if(broadcast_mode && packet->data[38] == 255) + if(broadcast_mode && packet->data[38] == 255) { route_broadcast(source, packet); - else + } else { route_ipv6_unicast(source, packet); + } } /* RFC 826 */ @@ -867,8 +948,9 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { subnet_t *subnet; struct in_addr addr; - if(!checklength(source, packet, ether_size + arp_size)) + if(!checklength(source, packet, ether_size + arp_size)) { return; + } if(source != myself) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname); @@ -877,8 +959,9 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { /* First, snatch the source address from the ARP packet */ - if(overwrite_mac) + if(overwrite_mac) { memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); + } /* Copy headers from packet to structs on the stack */ @@ -887,7 +970,7 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { /* Check if this is a valid ARP request */ if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || - arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) { + arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request"); return; } @@ -898,29 +981,31 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { if(!subnet) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d", - arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2], - arp.arp_tpa[3]); + arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2], + arp.arp_tpa[3]); return; } /* Check if it is for our own subnet */ - if(subnet->owner == myself) - return; /* silently ignore */ + if(subnet->owner == myself) { + return; /* silently ignore */ + } if(decrement_ttl) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ + packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - memcpy(&addr, arp.arp_tpa, sizeof(addr)); /* save protocol addr */ - memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */ - memcpy(arp.arp_spa, &addr, sizeof(addr)); /* ... */ + memcpy(&addr, arp.arp_tpa, sizeof(addr)); /* save protocol addr */ + memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */ + memcpy(arp.arp_spa, &addr, sizeof(addr)); /* ... */ - memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ - memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ + memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ arp.arp_op = htons(ARPOP_REPLY); /* Copy structs on stack back to packet */ @@ -957,29 +1042,33 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { return; } - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) { return; + } if(decrement_ttl && source != myself && subnet->owner != myself) - if(!do_decrement_ttl(source, packet)) + if(!do_decrement_ttl(source, packet)) { return; + } uint16_t type = packet->data[12] << 8 | packet->data[13]; if(priorityinheritance) { - if(type == ETH_P_IP && packet->len >= ether_size + ip_size) + if(type == ETH_P_IP && packet->len >= ether_size + ip_size) { packet->priority = packet->data[15]; - else if(type == ETH_P_IPV6 && packet->len >= ether_size + ip6_size) + } else if(type == ETH_P_IPV6 && packet->len >= ether_size + ip6_size) { packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4); + } } // Handle packets larger than PMTU node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; - if(directonly && subnet->owner != via) + if(directonly && subnet->owner != via) { return; - + } + if(via && packet->len > via->mtu && via != myself) { ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); length_t ethlen = 14; @@ -996,6 +1085,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { } else { fragment_ipv4_packet(via, packet, ethlen); } + return; } else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) { packet->len = via->mtu; @@ -1005,7 +1095,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } @@ -1015,40 +1105,40 @@ void route(node_t *source, vpn_packet_t *packet) { return; } - if(!checklength(source, packet, ether_size)) + if(!checklength(source, packet, ether_size)) { return; + } - switch (routing_mode) { - case RMODE_ROUTER: - { - uint16_t type = packet->data[12] << 8 | packet->data[13]; - - switch (type) { - case ETH_P_ARP: - route_arp(source, packet); - break; - - case ETH_P_IP: - route_ipv4(source, packet); - break; + switch(routing_mode) { + case RMODE_ROUTER: { + uint16_t type = packet->data[12] << 8 | packet->data[13]; - case ETH_P_IPV6: - route_ipv6(source, packet); - break; + switch(type) { + case ETH_P_ARP: + route_arp(source, packet); + break; - default: - ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type); - break; - } - } + case ETH_P_IP: + route_ipv4(source, packet); break; - case RMODE_SWITCH: - route_mac(source, packet); + case ETH_P_IPV6: + route_ipv6(source, packet); break; - case RMODE_HUB: - route_broadcast(source, packet); + default: + ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type); break; + } + } + break; + + case RMODE_SWITCH: + route_mac(source, packet); + break; + + case RMODE_HUB: + route_broadcast(source, packet); + break; } } diff --git a/src/route.h b/src/route.h index 74f7005..8681288 100644 --- a/src/route.h +++ b/src/route.h @@ -4,7 +4,7 @@ /* route.h -- header file for route.c Copyright (C) 2000-2005 Ivo Timmermans - 2000-2012 Guus Sliepen + 2000-2012 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/solaris/device.c b/src/solaris/device.c index 73046b8..527823e 100644 --- a/src/solaris/device.c +++ b/src/solaris/device.c @@ -62,33 +62,37 @@ static bool setup_device(void) { char *type; if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { - if(routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { device = xstrdup(DEFAULT_TUN_DEVICE); - else + } else { device = xstrdup(DEFAULT_TAP_DEVICE); + } } if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(!strcasecmp(type, "tun")) /* use default */; - else if(!strcasecmp(type, "tap")) + else if(!strcasecmp(type, "tap")) { device_type = DEVICE_TYPE_TAP; - else { + } else { logger(LOG_ERR, "Unknown device type %s!", type); return false; } } else { - if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) + if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) { device_type = DEVICE_TYPE_TAP; + } } - if(device_type == DEVICE_TYPE_TUN) + if(device_type == DEVICE_TYPE_TUN) { device_info = "Solaris tun device"; - else + } else { device_info = "Solaris tap device"; + } - if(device_type == DEVICE_TYPE_TAP && routing_mode == RMODE_ROUTER) + if(device_type == DEVICE_TYPE_TAP && routing_mode == RMODE_ROUTER) { overwrite_mac = true; + } /* The following is black magic copied from OpenVPN. */ @@ -107,8 +111,10 @@ static bool setup_device(void) { char *ptr = device; get_config_string(lookup_config(config_tree, "Interface"), &ptr); - while(*ptr && !isdigit(*ptr)) + while(*ptr && !isdigit(*ptr)) { ptr++; + } + int ppa = atoi(ptr); /* Assign a new PPA and get its unit number. */ @@ -116,20 +122,24 @@ static bool setup_device(void) { struct strioctl strioc_ppa = { .ic_cmd = TUNNEWPPA, .ic_len = sizeof(ppa), - .ic_dp = (char *)&ppa, + .ic_dp = (char *) &ppa, }; if(!*ptr) { /* no number given, try dynamic */ bool found = false; + while(!found && ppa < 64) { int new_ppa = ioctl(device_fd, I_STR, &strioc_ppa); + if(new_ppa >= 0) { ppa = new_ppa; found = true; break; } + ppa++; } + if(!found) { logger(LOG_ERR, "Could not find free PPA for %s %s!", device_info, device); return false; @@ -157,6 +167,7 @@ static bool setup_device(void) { /* Remove muxes just in case they are left over from a crashed tincd */ struct lifreq ifr = {}; strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name)); + if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) { int muxid = ifr.lifr_arp_muxid; ioctl(ip_fd, I_PUNLINK, muxid); @@ -191,6 +202,7 @@ static bool setup_device(void) { logger(LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device); return false; } + if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) { logger(LOG_ERR, "Could not set flags on %s %s!", device_info, device); return false; @@ -204,8 +216,9 @@ static bool setup_device(void) { /* Pop any modules on the stream */ while(true) { - if(ioctl(ip_fd, I_POP, NULL) < 0) + if(ioctl(ip_fd, I_POP, NULL) < 0) { break; + } } /* Push arp module to ip_fd */ @@ -230,7 +243,7 @@ static bool setup_device(void) { struct strioctl strioc_if = { .ic_cmd = SIOCSLIFNAME, .ic_len = sizeof(ifr), - .ic_dp = (char *)&ifr, + .ic_dp = (char *) &ifr, }; if(ioctl(arp_fd, I_STR, &strioc_if) < 0) { @@ -251,12 +264,16 @@ static bool setup_device(void) { logger(LOG_ERR, "Could not link %s %s to ARP", device_info, device); return false; } + close(arp_fd); } struct lifreq ifr = {}; + strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name)); + ifr.lifr_ip_muxid = ip_muxid; + if(device_type == DEVICE_TYPE_TAP) { ifr.lifr_arp_muxid = arp_muxid; } @@ -265,6 +282,7 @@ static bool setup_device(void) { if(device_type == DEVICE_TYPE_TAP) { ioctl(ip_fd, I_PUNLINK, arp_muxid); } + ioctl(ip_fd, I_PUNLINK, ip_muxid); logger(LOG_ERR, "Could not set multiplexor id for %s %s", device_info, device); return false; @@ -286,6 +304,7 @@ static void close_device(void) { if(iface) { struct lifreq ifr = {}; strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name)); + if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) { int muxid = ifr.lifr_arp_muxid; ioctl(ip_fd, I_PUNLINK, muxid); @@ -307,47 +326,49 @@ static bool read_packet(vpn_packet_t *packet) { int f = 0; switch(device_type) { - case DEVICE_TYPE_TUN: - sbuf.maxlen = MTU - 14; - sbuf.buf = (char *)packet->data + 14; + case DEVICE_TYPE_TUN: + sbuf.maxlen = MTU - 14; + sbuf.buf = (char *)packet->data + 14; - if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); - return false; - } + if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); + return false; + } - switch(packet->data[14] >> 4) { - case 4: - packet->data[12] = 0x08; - packet->data[13] = 0x00; - break; - case 6: - packet->data[12] = 0x86; - packet->data[13] = 0xDD; - break; - default: - ifdebug(TRAFFIC) logger(LOG_ERR, "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device); - return false; - } + switch(packet->data[14] >> 4) { + case 4: + packet->data[12] = 0x08; + packet->data[13] = 0x00; + break; - memset(packet->data, 0, 12); - packet->len = sbuf.len + 14; + case 6: + packet->data[12] = 0x86; + packet->data[13] = 0xDD; break; - case DEVICE_TYPE_TAP: - sbuf.maxlen = MTU; - sbuf.buf = (char *)packet->data; + default: + ifdebug(TRAFFIC) logger(LOG_ERR, "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device); + return false; + } - if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); - return false; - } + memset(packet->data, 0, 12); + packet->len = sbuf.len + 14; + break; - packet->len = sbuf.len; - break; + case DEVICE_TYPE_TAP: + sbuf.maxlen = MTU; + sbuf.buf = (char *)packet->data; - default: - abort(); + if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); + return false; + } + + packet->len = sbuf.len; + break; + + default: + abort(); } device_total_in += packet->len; @@ -363,28 +384,30 @@ static bool write_packet(vpn_packet_t *packet) { struct strbuf sbuf; switch(device_type) { - case DEVICE_TYPE_TUN: - sbuf.len = packet->len - 14; - sbuf.buf = (char *)packet->data + 14; + case DEVICE_TYPE_TUN: + sbuf.len = packet->len - 14; + sbuf.buf = (char *)packet->data + 14; - if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); - return false; - } - break; + if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); + return false; + } - case DEVICE_TYPE_TAP: - sbuf.len = packet->len; - sbuf.buf = (char *)packet->data; + break; - if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); - return false; - } - break; + case DEVICE_TYPE_TAP: + sbuf.len = packet->len; + sbuf.buf = (char *)packet->data; - default: - abort(); + if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { + logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); + return false; + } + + break; + + default: + abort(); } device_total_out += packet->len; diff --git a/src/subnet.c b/src/subnet.c index 43a7ad2..b4c7913 100644 --- a/src/subnet.c +++ b/src/subnet.c @@ -65,13 +65,15 @@ static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) { result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t)); - if(result) + if(result) { return result; - + } + result = a->weight - b->weight; - if(result || !a->owner || !b->owner) + if(result || !a->owner || !b->owner) { return result; + } return strcmp(a->owner->name, b->owner->name); } @@ -81,18 +83,21 @@ static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) { result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength; - if(result) + if(result) { return result; + } result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t)); - if(result) + if(result) { return result; - + } + result = a->weight - b->weight; - if(result || !a->owner || !b->owner) + if(result || !a->owner || !b->owner) { return result; + } return strcmp(a->owner->name, b->owner->name); } @@ -102,18 +107,21 @@ static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) { result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength; - if(result) + if(result) { return result; - + } + result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t)); - if(result) + if(result) { return result; - + } + result = a->weight - b->weight; - if(result || !a->owner || !b->owner) + if(result || !a->owner || !b->owner) { return result; + } return strcmp(a->owner->name, b->owner->name); } @@ -123,19 +131,23 @@ int subnet_compare(const subnet_t *a, const subnet_t *b) { result = a->type - b->type; - if(result) + if(result) { return result; + } - switch (a->type) { + switch(a->type) { case SUBNET_MAC: return subnet_compare_mac(a, b); + case SUBNET_IPV4: return subnet_compare_ipv4(a, b); + case SUBNET_IPV6: return subnet_compare_ipv6(a, b); + default: logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!", - a->type); + a->type); exit(0); } @@ -198,17 +210,20 @@ bool str2net(subnet_t *subnet, const char *subnetstr) { int weight = 10; if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d", - &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) { - if(l < 0 || l > 32) + &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) { + if(l < 0 || l > 32) { return false; + } subnet->type = SUBNET_IPV4; subnet->net.ipv4.prefixlength = l; subnet->weight = weight; for(i = 0; i < 4; i++) { - if(x[i] > 255) + if(x[i] > 255) { return false; + } + subnet->net.ipv4.address.x[i] = x[i]; } @@ -216,17 +231,19 @@ bool str2net(subnet_t *subnet, const char *subnetstr) { } if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], - &l, &weight) >= 9) { - if(l < 0 || l > 128) + &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], + &l, &weight) >= 9) { + if(l < 0 || l > 128) { return false; + } subnet->type = SUBNET_IPV6; subnet->net.ipv6.prefixlength = l; subnet->weight = weight; - for(i = 0; i < 8; i++) + for(i = 0; i < 8; i++) { subnet->net.ipv6.address.x[i] = htons(x[i]); + } return true; } @@ -237,8 +254,10 @@ bool str2net(subnet_t *subnet, const char *subnetstr) { subnet->weight = weight; for(i = 0; i < 4; i++) { - if(x[i] > 255) + if(x[i] > 255) { return false; + } + subnet->net.ipv4.address.x[i] = x[i]; } @@ -246,24 +265,26 @@ bool str2net(subnet_t *subnet, const char *subnetstr) { } if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) { + &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) { subnet->type = SUBNET_IPV6; subnet->net.ipv6.prefixlength = 128; subnet->weight = weight; - for(i = 0; i < 8; i++) + for(i = 0; i < 8; i++) { subnet->net.ipv6.address.x[i] = htons(x[i]); + } return true; } if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) { + &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) { subnet->type = SUBNET_MAC; subnet->weight = weight; - for(i = 0; i < 6; i++) + for(i = 0; i < 6; i++) { subnet->net.mac.address.x[i] = x[i]; + } return true; } @@ -276,66 +297,87 @@ bool str2net(subnet_t *subnet, const char *subnetstr) { // Count number of colons for(p = subnetstr; *p; p++) - if(*p == ':') + if(*p == ':') { colons++; + } - if(colons > 7) + if(colons > 7) { return false; + } // Scan numbers before the double colon p = subnetstr; + for(i = 0; i < colons; i++) { - if(*p == ':') + if(*p == ':') { break; + } + x[i] = strtoul(p, &q, 0x10); - if(!q || p == q || *q != ':') + + if(!q || p == q || *q != ':') { return false; + } + p = ++q; } p++; colons -= i; + if(!i) { p++; colons--; } - if(!*p || *p == '/' || *p == '#') + if(!*p || *p == '/' || *p == '#') { colons--; + } // Fill in the blanks - for(; i < 8 - colons; i++) + for(; i < 8 - colons; i++) { x[i] = 0; + } // Scan the remaining numbers for(; i < 8; i++) { x[i] = strtoul(p, &q, 0x10); - if(!q || p == q) + + if(!q || p == q) { return false; + } + if(i == 7) { p = q; break; } - if(*q != ':') + + if(*q != ':') { return false; + } + p = ++q; } l = 128; - if(*p == '/') + + if(*p == '/') { sscanf(p, "/%d#%d", &l, &weight); - else if(*p == '#') + } else if(*p == '#') { sscanf(p, "#%d", &weight); + } - if(l < 0 || l > 128) + if(l < 0 || l > 128) { return false; + } subnet->type = SUBNET_IPV6; subnet->net.ipv6.prefixlength = l; subnet->weight = weight; - for(i = 0; i < 8; i++) + for(i = 0; i < 8; i++) { subnet->net.ipv6.address.x[i] = htons(x[i]); + } return true; } @@ -349,47 +391,47 @@ bool net2str(char *netstr, int len, const subnet_t *subnet) { return false; } - switch (subnet->type) { - case SUBNET_MAC: - snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d", - subnet->net.mac.address.x[0], - subnet->net.mac.address.x[1], - subnet->net.mac.address.x[2], - subnet->net.mac.address.x[3], - subnet->net.mac.address.x[4], - subnet->net.mac.address.x[5], - subnet->weight); - break; - - case SUBNET_IPV4: - snprintf(netstr, len, "%u.%u.%u.%u/%d#%d", - subnet->net.ipv4.address.x[0], - subnet->net.ipv4.address.x[1], - subnet->net.ipv4.address.x[2], - subnet->net.ipv4.address.x[3], - subnet->net.ipv4.prefixlength, - subnet->weight); - break; - - case SUBNET_IPV6: - snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d", - ntohs(subnet->net.ipv6.address.x[0]), - ntohs(subnet->net.ipv6.address.x[1]), - ntohs(subnet->net.ipv6.address.x[2]), - ntohs(subnet->net.ipv6.address.x[3]), - ntohs(subnet->net.ipv6.address.x[4]), - ntohs(subnet->net.ipv6.address.x[5]), - ntohs(subnet->net.ipv6.address.x[6]), - ntohs(subnet->net.ipv6.address.x[7]), - subnet->net.ipv6.prefixlength, - subnet->weight); - break; - - default: - logger(LOG_ERR, - "net2str() was called with unknown subnet type %d, exiting!", - subnet->type); - exit(0); + switch(subnet->type) { + case SUBNET_MAC: + snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d", + subnet->net.mac.address.x[0], + subnet->net.mac.address.x[1], + subnet->net.mac.address.x[2], + subnet->net.mac.address.x[3], + subnet->net.mac.address.x[4], + subnet->net.mac.address.x[5], + subnet->weight); + break; + + case SUBNET_IPV4: + snprintf(netstr, len, "%u.%u.%u.%u/%d#%d", + subnet->net.ipv4.address.x[0], + subnet->net.ipv4.address.x[1], + subnet->net.ipv4.address.x[2], + subnet->net.ipv4.address.x[3], + subnet->net.ipv4.prefixlength, + subnet->weight); + break; + + case SUBNET_IPV6: + snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d", + ntohs(subnet->net.ipv6.address.x[0]), + ntohs(subnet->net.ipv6.address.x[1]), + ntohs(subnet->net.ipv6.address.x[2]), + ntohs(subnet->net.ipv6.address.x[3]), + ntohs(subnet->net.ipv6.address.x[4]), + ntohs(subnet->net.ipv6.address.x[5]), + ntohs(subnet->net.ipv6.address.x[6]), + ntohs(subnet->net.ipv6.address.x[7]), + subnet->net.ipv6.prefixlength, + subnet->weight); + break; + + default: + logger(LOG_ERR, + "net2str() was called with unknown subnet type %d, exiting!", + subnet->type); + exit(0); } return true; @@ -409,26 +451,34 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) { // Check if this address is cached for(i = 0; i < 2; i++) { - if(!cache_mac_valid[i]) + if(!cache_mac_valid[i]) { continue; - if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) + } + + if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) { continue; - if(!memcmp(address, &cache_mac_address[i], sizeof(*address))) + } + + if(!memcmp(address, &cache_mac_address[i], sizeof(*address))) { return cache_mac_subnet[i]; + } } // Search all subnets for a matching one for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) { p = n->data; - - if(!p || p->type != SUBNET_MAC) + + if(!p || p->type != SUBNET_MAC) { continue; + } if(!memcmp(address, &p->net.mac.address, sizeof(*address))) { r = p; - if(p->owner->status.reachable) + + if(p->owner->status.reachable) { break; + } } } @@ -450,24 +500,30 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) { // Check if this address is cached for(i = 0; i < 2; i++) { - if(!cache_ipv4_valid[i]) + if(!cache_ipv4_valid[i]) { continue; - if(!memcmp(address, &cache_ipv4_address[i], sizeof(*address))) + } + + if(!memcmp(address, &cache_ipv4_address[i], sizeof(*address))) { return cache_ipv4_subnet[i]; + } } // Search all subnets for a matching one for(n = subnet_tree->head; n; n = n->next) { p = n->data; - - if(!p || p->type != SUBNET_IPV4) + + if(!p || p->type != SUBNET_IPV4) { continue; + } if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) { r = p; - if(p->owner->status.reachable) + + if(p->owner->status.reachable) { break; + } } } @@ -489,24 +545,30 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) { // Check if this address is cached for(i = 0; i < 2; i++) { - if(!cache_ipv6_valid[i]) + if(!cache_ipv6_valid[i]) { continue; - if(!memcmp(address, &cache_ipv6_address[i], sizeof(*address))) + } + + if(!memcmp(address, &cache_ipv6_address[i], sizeof(*address))) { return cache_ipv6_subnet[i]; + } } // Search all subnets for a matching one for(n = subnet_tree->head; n; n = n->next) { p = n->data; - - if(!p || p->type != SUBNET_IPV6) + + if(!p || p->type != SUBNET_IPV6) { continue; + } if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) { r = p; - if(p->owner->status.reachable) + + if(p->owner->status.reachable) { break; + } } } @@ -550,20 +612,29 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) { if(!subnet) { for(node = owner->subnet_tree->head; node; node = node->next) { subnet = node->data; - if(!net2str(netstr, sizeof(netstr), subnet)) + + if(!net2str(netstr, sizeof(netstr), subnet)) { continue; + } + // Strip the weight from the subnet, and put it in its own environment variable char *weight = strchr(netstr, '#'); - if(weight) + + if(weight) { *weight++ = 0; - else + } else { weight = empty; + } // Prepare the SUBNET and WEIGHT variables - if(envp[5]) + if(envp[5]) { free(envp[5]); - if(envp[6]) + } + + if(envp[6]) { free(envp[6]); + } + xasprintf(&envp[5], "SUBNET=%s", netstr); xasprintf(&envp[6], "WEIGHT=%s", weight); @@ -573,10 +644,12 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) { if(net2str(netstr, sizeof(netstr), subnet)) { // Strip the weight from the subnet, and put it in its own environment variable char *weight = strchr(netstr, '#'); - if(weight) + + if(weight) { *weight++ = 0; - else + } else { weight = empty; + } // Prepare the SUBNET and WEIGHT variables xasprintf(&envp[5], "SUBNET=%s", netstr); @@ -586,8 +659,9 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) { } } - for(i = 0; envp[i] && i < 9; i++) + for(i = 0; envp[i] && i < 9; i++) { free(envp[i]); + } } void dump_subnets(void) { @@ -599,8 +673,11 @@ void dump_subnets(void) { for(node = subnet_tree->head; node; node = node->next) { subnet = node->data; - if(!net2str(netstr, sizeof(netstr), subnet)) + + if(!net2str(netstr, sizeof(netstr), subnet)) { continue; + } + logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name); } diff --git a/src/subnet.h b/src/subnet.h index 878d877..c764943 100644 --- a/src/subnet.h +++ b/src/subnet.h @@ -27,7 +27,7 @@ typedef enum subnet_type_t { SUBNET_MAC = 0, SUBNET_IPV4, SUBNET_IPV6, - SUBNET_TYPES /* Guardian */ + SUBNET_TYPES /* Guardian */ } subnet_type_t; typedef struct subnet_mac_t { @@ -47,11 +47,11 @@ typedef struct subnet_ipv6_t { #include "node.h" typedef struct subnet_t { - struct node_t *owner; /* the owner of this subnet */ + struct node_t *owner; /* the owner of this subnet */ - subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */ - time_t expires; /* expiry time */ - int weight; /* weight (higher value is higher priority) */ + subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */ + time_t expires; /* expiry time */ + int weight; /* weight (higher value is higher priority) */ /* And now for the actual subnet: */ @@ -67,11 +67,11 @@ typedef struct subnet_t { extern avl_tree_t *subnet_tree; extern int subnet_compare(const struct subnet_t *, const struct subnet_t *); -extern subnet_t *new_subnet(void) __attribute__ ((__malloc__)); +extern subnet_t *new_subnet(void) __attribute__((__malloc__)); extern void free_subnet(subnet_t *); extern void init_subnets(void); extern void exit_subnets(void); -extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__)); +extern avl_tree_t *new_subnet_tree(void) __attribute__((__malloc__)); extern void free_subnet_tree(avl_tree_t *); extern void subnet_add(struct node_t *, subnet_t *); extern void subnet_del(struct node_t *, subnet_t *); diff --git a/src/tincd.c b/src/tincd.c index c731e1d..db6b213 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -97,10 +97,10 @@ static const char *switchuser = NULL; /* If nonzero, write log entries to a separate file. */ bool use_logfile = false; -char *identname = NULL; /* program name for syslog */ -char *pidfilename = NULL; /* pid file location */ -char *logfilename = NULL; /* log file location */ -char **g_argv; /* a copy of the cmdline arguments */ +char *identname = NULL; /* program name for syslog */ +char *pidfilename = NULL; /* pid file location */ +char *logfilename = NULL; /* log file location */ +char **g_argv; /* a copy of the cmdline arguments */ static int status = 1; @@ -132,23 +132,23 @@ int main2(int argc, char **argv); static void usage(bool status) { if(status) fprintf(stderr, "Try `%s --help\' for more information.\n", - program_name); + program_name); else { printf("Usage: %s [option]...\n\n", program_name); printf(" -c, --config=DIR Read configuration options from DIR.\n" - " -D, --no-detach Don't fork and detach.\n" - " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" - " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" - " -n, --net=NETNAME Connect to net NETNAME.\n" - " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" - " -L, --mlock Lock tinc into main memory.\n" - " --logfile[=FILENAME] Write log entries to a logfile.\n" - " --pidfile=FILENAME Write PID to FILENAME.\n" - " -o, --option=[HOST.]KEY=VALUE Set global/host configuration value.\n" - " -R, --chroot chroot to NET dir at startup.\n" - " -U, --user=USER setuid to given USER at startup.\n" - " --help Display this help and exit.\n" - " --version Output version information and exit.\n\n"); + " -D, --no-detach Don't fork and detach.\n" + " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" + " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" + " -n, --net=NETNAME Connect to net NETNAME.\n" + " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" + " -L, --mlock Lock tinc into main memory.\n" + " --logfile[=FILENAME] Write log entries to a logfile.\n" + " --pidfile=FILENAME Write PID to FILENAME.\n" + " -o, --option=[HOST.]KEY=VALUE Set global/host configuration value.\n" + " -R, --chroot chroot to NET dir at startup.\n" + " -U, --user=USER setuid to given USER at startup.\n" + " --help Display this help and exit.\n" + " --version Output version information and exit.\n\n"); printf("Report bugs to tinc@tinc-vpn.org.\n"); } } @@ -162,166 +162,192 @@ static bool parse_options(int argc, char **argv) { cmdline_conf = list_alloc((list_action_t)free_config); while((r = getopt_long(argc, argv, "c:DLd::k::n:o:K::RU:", long_options, &option_index)) != EOF) { - switch (r) { - case 0: /* long option */ - break; + switch(r) { + case 0: /* long option */ + break; - case 'c': /* config file */ - if(confbase) { - fprintf(stderr, "Only one configuration directory can be given.\n"); - usage(true); - return false; - } - confbase = xstrdup(optarg); - break; + case 'c': /* config file */ + if(confbase) { + fprintf(stderr, "Only one configuration directory can be given.\n"); + usage(true); + return false; + } - case 'D': /* no detach */ - do_detach = false; - break; + confbase = xstrdup(optarg); + break; - case 'L': /* no detach */ + case 'D': /* no detach */ + do_detach = false; + break; + + case 'L': /* no detach */ #ifndef HAVE_MLOCKALL - logger(LOG_ERR, "%s not supported on this platform", "mlockall()"); - return false; + logger(LOG_ERR, "%s not supported on this platform", "mlockall()"); + return false; #else - do_mlock = true; - break; + do_mlock = true; + break; #endif - case 'd': /* increase debug level */ - if(!optarg && optind < argc && *argv[optind] != '-') - optarg = argv[optind++]; - if(optarg) - debug_level = atoi(optarg); - else - debug_level++; - break; + case 'd': /* increase debug level */ + if(!optarg && optind < argc && *argv[optind] != '-') { + optarg = argv[optind++]; + } + + if(optarg) { + debug_level = atoi(optarg); + } else { + debug_level++; + } + + break; - case 'k': /* kill old tincds */ + case 'k': /* kill old tincds */ #ifndef HAVE_MINGW - if(!optarg && optind < argc && *argv[optind] != '-') - optarg = argv[optind++]; - if(optarg) { - if(!strcasecmp(optarg, "HUP")) - kill_tincd = SIGHUP; - else if(!strcasecmp(optarg, "TERM")) - kill_tincd = SIGTERM; - else if(!strcasecmp(optarg, "KILL")) - kill_tincd = SIGKILL; - else if(!strcasecmp(optarg, "USR1")) - kill_tincd = SIGUSR1; - else if(!strcasecmp(optarg, "USR2")) - kill_tincd = SIGUSR2; - else if(!strcasecmp(optarg, "WINCH")) - kill_tincd = SIGWINCH; - else if(!strcasecmp(optarg, "INT")) - kill_tincd = SIGINT; - else if(!strcasecmp(optarg, "ALRM")) - kill_tincd = SIGALRM; - else if(!strcasecmp(optarg, "ABRT")) - kill_tincd = SIGABRT; - else { - kill_tincd = atoi(optarg); - - if(!kill_tincd) { - fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n", - optarg); - usage(true); - return false; - } - } - } else + if(!optarg && optind < argc && *argv[optind] != '-') { + optarg = argv[optind++]; + } + + if(optarg) { + if(!strcasecmp(optarg, "HUP")) { + kill_tincd = SIGHUP; + } else if(!strcasecmp(optarg, "TERM")) { kill_tincd = SIGTERM; + } else if(!strcasecmp(optarg, "KILL")) { + kill_tincd = SIGKILL; + } else if(!strcasecmp(optarg, "USR1")) { + kill_tincd = SIGUSR1; + } else if(!strcasecmp(optarg, "USR2")) { + kill_tincd = SIGUSR2; + } else if(!strcasecmp(optarg, "WINCH")) { + kill_tincd = SIGWINCH; + } else if(!strcasecmp(optarg, "INT")) { + kill_tincd = SIGINT; + } else if(!strcasecmp(optarg, "ALRM")) { + kill_tincd = SIGALRM; + } else if(!strcasecmp(optarg, "ABRT")) { + kill_tincd = SIGABRT; + } else { + kill_tincd = atoi(optarg); + + if(!kill_tincd) { + fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n", + optarg); + usage(true); + return false; + } + } + } else { + kill_tincd = SIGTERM; + } + #else - kill_tincd = 1; + kill_tincd = 1; #endif - break; + break; - case 'n': /* net name given */ - /* netname "." is special: a "top-level name" */ - if(netname) { - fprintf(stderr, "Only one netname can be given.\n"); + case 'n': /* net name given */ + + /* netname "." is special: a "top-level name" */ + if(netname) { + fprintf(stderr, "Only one netname can be given.\n"); + usage(true); + return false; + } + + if(optarg && strcmp(optarg, ".")) { + netname = xstrdup(optarg); + } + + break; + + case 'o': /* option */ + cfg = parse_config_line(optarg, NULL, ++lineno); + + if(!cfg) { + return false; + } + + list_insert_tail(cmdline_conf, cfg); + break; + + case 'K': /* generate public/private keypair */ + if(!optarg && optind < argc && *argv[optind] != '-') { + optarg = argv[optind++]; + } + + if(optarg) { + generate_keys = atoi(optarg); + + if(generate_keys < 512) { + fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n", + optarg); usage(true); return false; } - if(optarg && strcmp(optarg, ".")) - netname = xstrdup(optarg); - break; - case 'o': /* option */ - cfg = parse_config_line(optarg, NULL, ++lineno); - if (!cfg) - return false; - list_insert_tail(cmdline_conf, cfg); - break; - - case 'K': /* generate public/private keypair */ - if(!optarg && optind < argc && *argv[optind] != '-') - optarg = argv[optind++]; - if(optarg) { - generate_keys = atoi(optarg); - - if(generate_keys < 512) { - fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n", - optarg); - usage(true); - return false; - } + generate_keys &= ~7; /* Round it to bytes */ + } else { + generate_keys = 2048; + } - generate_keys &= ~7; /* Round it to bytes */ - } else - generate_keys = 2048; - break; - - case 'R': /* chroot to NETNAME dir */ - do_chroot = true; - break; - - case 'U': /* setuid to USER */ - switchuser = optarg; - break; - - case 1: /* show help */ - show_help = true; - break; - - case 2: /* show version */ - show_version = true; - break; - - case 3: /* bypass security */ - bypass_security = true; - break; - - case 4: /* write log entries to a file */ - use_logfile = true; - if(!optarg && optind < argc && *argv[optind] != '-') - optarg = argv[optind++]; - if(optarg) { - if(logfilename) { - fprintf(stderr, "Only one logfile can be given.\n"); - usage(true); - return false; - } - logfilename = xstrdup(optarg); - } - break; + break; - case 5: /* write PID to a file */ - if(pidfilename) { - fprintf(stderr, "Only one pidfile can be given.\n"); + case 'R': /* chroot to NETNAME dir */ + do_chroot = true; + break; + + case 'U': /* setuid to USER */ + switchuser = optarg; + break; + + case 1: /* show help */ + show_help = true; + break; + + case 2: /* show version */ + show_version = true; + break; + + case 3: /* bypass security */ + bypass_security = true; + break; + + case 4: /* write log entries to a file */ + use_logfile = true; + + if(!optarg && optind < argc && *argv[optind] != '-') { + optarg = argv[optind++]; + } + + if(optarg) { + if(logfilename) { + fprintf(stderr, "Only one logfile can be given.\n"); usage(true); return false; } - pidfilename = xstrdup(optarg); - break; - case '?': + logfilename = xstrdup(optarg); + } + + break; + + case 5: /* write PID to a file */ + if(pidfilename) { + fprintf(stderr, "Only one pidfile can be given.\n"); usage(true); return false; + } + + pidfilename = xstrdup(optarg); + break; - default: - break; + case '?': + usage(true); + return false; + + default: + break; } } @@ -337,36 +363,37 @@ static bool parse_options(int argc, char **argv) { /* This function prettyprints the key generation process */ static int indicator(int a, int b, BN_GENCB *cb) { - switch (a) { - case 0: - fprintf(stderr, "."); - break; - - case 1: - fprintf(stderr, "+"); - break; + switch(a) { + case 0: + fprintf(stderr, "."); + break; - case 2: - fprintf(stderr, "-"); - break; + case 1: + fprintf(stderr, "+"); + break; - case 3: - switch (b) { - case 0: - fprintf(stderr, " p\n"); - break; + case 2: + fprintf(stderr, "-"); + break; - case 1: - fprintf(stderr, " q\n"); - break; + case 3: + switch(b) { + case 0: + fprintf(stderr, " p\n"); + break; - default: - fprintf(stderr, "?"); - } + case 1: + fprintf(stderr, " q\n"); break; default: fprintf(stderr, "?"); + } + + break; + + default: + fprintf(stderr, "?"); } return 1; @@ -397,14 +424,19 @@ static bool keygen(int bits) { fprintf(stderr, "Generating %d bits keys:\n", bits); cb = BN_GENCB_new(); - if(!cb) + + if(!cb) { abort(); + } + BN_GENCB_set(cb, indicator, NULL); rsa_key = RSA_new(); BN_hex2bn(&e, "10001"); - if(!rsa_key || !e) + + if(!rsa_key || !e) { abort(); + } result = RSA_generate_key_ex(rsa_key, bits, e, cb); @@ -415,8 +447,9 @@ static bool keygen(int bits) { fprintf(stderr, "Error during key generation!\n"); RSA_free(rsa_key); return false; - } else + } else { fprintf(stderr, "Done.\n"); + } snprintf(filename, sizeof(filename), "%s/rsa_key.priv", confbase); f = ask_and_open(filename, "private RSA key"); @@ -430,7 +463,7 @@ static bool keygen(int bits) { /* Make it unreadable for others. */ fchmod(fileno(f), 0600); #endif - + fputc('\n', f); PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL); fclose(f); @@ -470,101 +503,141 @@ static void make_names(void) { DWORD len = sizeof(installdir); #endif - if(netname) + if(netname) { xasprintf(&identname, "tinc.%s", netname); - else + } else { identname = xstrdup("tinc"); + } #ifdef HAVE_MINGW + if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) { if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) { if(!confbase) { - if(netname) + if(netname) { xasprintf(&confbase, "%s/%s", installdir, netname); - else + } else { xasprintf(&confbase, "%s", installdir); + } } - if(!logfilename) + + if(!logfilename) { xasprintf(&logfilename, "%s/tinc.log", confbase); + } } + RegCloseKey(key); - if(*installdir) + + if(*installdir) { return; + } } + #endif - if(!pidfilename) + if(!pidfilename) { xasprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname); + } - if(!logfilename) + if(!logfilename) { xasprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname); + } if(netname) { - if(!confbase) + if(!confbase) { xasprintf(&confbase, CONFDIR "/tinc/%s", netname); - else + } else { logger(LOG_INFO, "Both netname and configuration directory given, using the latter..."); + } } else { - if(!confbase) + if(!confbase) { xasprintf(&confbase, CONFDIR "/tinc"); + } } } static void free_names() { - if (identname) free(identname); - if (netname) free(netname); - if (pidfilename) free(pidfilename); - if (logfilename) free(logfilename); - if (confbase) free(confbase); + if(identname) { + free(identname); + } + + if(netname) { + free(netname); + } + + if(pidfilename) { + free(pidfilename); + } + + if(logfilename) { + free(logfilename); + } + + if(confbase) { + free(confbase); + } } static bool drop_privs() { #ifdef HAVE_MINGW - if (switchuser) { + + if(switchuser) { logger(LOG_ERR, "%s not supported on this platform", "-U"); return false; } - if (do_chroot) { + + if(do_chroot) { logger(LOG_ERR, "%s not supported on this platform", "-R"); return false; } + #else uid_t uid = 0; - if (switchuser) { + + if(switchuser) { struct passwd *pw = getpwnam(switchuser); - if (!pw) { + + if(!pw) { logger(LOG_ERR, "unknown user `%s'", switchuser); return false; } + uid = pw->pw_uid; - if (initgroups(switchuser, pw->pw_gid) != 0 || - setgid(pw->pw_gid) != 0) { + + if(initgroups(switchuser, pw->pw_gid) != 0 || + setgid(pw->pw_gid) != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "initgroups", strerror(errno)); return false; } + #ifndef ANDROID // Not supported in android NDK endgrent(); endpwent(); #endif } - if (do_chroot) { - tzset(); /* for proper timestamps in logs */ - if (chroot(confbase) != 0 || chdir("/") != 0) { + + if(do_chroot) { + tzset(); /* for proper timestamps in logs */ + + if(chroot(confbase) != 0 || chdir("/") != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "chroot", strerror(errno)); return false; } + free(confbase); confbase = xstrdup(""); } - if (switchuser) - if (setuid(uid) != 0) { + + if(switchuser) + if(setuid(uid) != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "setuid", strerror(errno)); return false; } + #endif return true; } @@ -581,18 +654,19 @@ static bool drop_privs() { int main(int argc, char **argv) { program_name = argv[0]; - if(!parse_options(argc, argv)) + if(!parse_options(argc, argv)) { return 1; - + } + make_names(); if(show_version) { printf("%s version %s\n", PACKAGE, VERSION); printf("Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen and others.\n" - "See the AUTHORS file for a complete list.\n\n" - "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to redistribute it under certain conditions;\n" - "see the file COPYING for details.\n"); + "See the AUTHORS file for a complete list.\n\n" + "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" + "and you are welcome to redistribute it under certain conditions;\n" + "see the file COPYING for details.\n"); return 0; } @@ -602,15 +676,18 @@ int main(int argc, char **argv) { return 0; } - if(kill_tincd) + if(kill_tincd) { return !kill_other(kill_tincd); + } - openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR); + openlogger("tinc", use_logfile ? LOGMODE_FILE : LOGMODE_STDERR); g_argv = argv; - if(getenv("LISTEN_PID") && atoi(getenv("LISTEN_PID")) == getpid()) + if(getenv("LISTEN_PID") && atoi(getenv("LISTEN_PID")) == getpid()) { do_detach = false; + } + #ifdef HAVE_UNSETENV unsetenv("LISTEN_PID"); #endif @@ -631,52 +708,61 @@ int main(int argc, char **argv) { return !keygen(generate_keys); } - if(!read_server_config()) + if(!read_server_config()) { return 1; + } #ifdef HAVE_LZO + if(lzo_init() != LZO_E_OK) { logger(LOG_ERR, "Error initializing LZO compressor!"); return 1; } + #endif #ifdef HAVE_MINGW + if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { logger(LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError())); return 1; } - if(!do_detach || !init_service()) + if(!do_detach || !init_service()) { return main2(argc, argv); - else + } else { return 1; + } } int main2(int argc, char **argv) { InitializeCriticalSection(&mutex); EnterCriticalSection(&mutex); #endif - char *priority = NULL; + char *priority = NULL; - if(!detach()) + if(!detach()) { return 1; + } #ifdef HAVE_MLOCKALL + /* Lock all pages into memory if requested. * This has to be done after daemon()/fork() so it works for child. * No need to do that in parent as it's very short-lived. */ if(do_mlock && mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "mlockall", - strerror(errno)); + strerror(errno)); return 1; } + #endif /* Setup sockets and open device. */ - if(!setup_network()) + if(!setup_network()) { goto end; + } /* Initiate all outgoing connections. */ @@ -684,34 +770,35 @@ int main2(int argc, char **argv) { /* Change process priority */ - if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) { - if(!strcasecmp(priority, "Normal")) { - if (setpriority(NORMAL_PRIORITY_CLASS) != 0) { - logger(LOG_ERR, "System call `%s' failed: %s", - "setpriority", strerror(errno)); - goto end; - } - } else if(!strcasecmp(priority, "Low")) { - if (setpriority(BELOW_NORMAL_PRIORITY_CLASS) != 0) { - logger(LOG_ERR, "System call `%s' failed: %s", - "setpriority", strerror(errno)); - goto end; - } - } else if(!strcasecmp(priority, "High")) { - if (setpriority(HIGH_PRIORITY_CLASS) != 0) { - logger(LOG_ERR, "System call `%s' failed: %s", - "setpriority", strerror(errno)); - goto end; - } - } else { - logger(LOG_ERR, "Invalid priority `%s`!", priority); - goto end; - } - } + if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) { + if(!strcasecmp(priority, "Normal")) { + if(setpriority(NORMAL_PRIORITY_CLASS) != 0) { + logger(LOG_ERR, "System call `%s' failed: %s", + "setpriority", strerror(errno)); + goto end; + } + } else if(!strcasecmp(priority, "Low")) { + if(setpriority(BELOW_NORMAL_PRIORITY_CLASS) != 0) { + logger(LOG_ERR, "System call `%s' failed: %s", + "setpriority", strerror(errno)); + goto end; + } + } else if(!strcasecmp(priority, "High")) { + if(setpriority(HIGH_PRIORITY_CLASS) != 0) { + logger(LOG_ERR, "System call `%s' failed: %s", + "setpriority", strerror(errno)); + goto end; + } + } else { + logger(LOG_ERR, "Invalid priority `%s`!", priority); + goto end; + } + } /* drop privileges */ - if (!drop_privs()) + if(!drop_privs()) { goto end; + } /* Start main loop. It only exits when tinc is killed. */ @@ -720,7 +807,7 @@ int main2(int argc, char **argv) { /* Shutdown properly. */ ifdebug(CONNECTIONS) - devops.dump_stats(); + devops.dump_stats(); close_network_connections(); diff --git a/src/uml_device.c b/src/uml_device.c index 5dcf8aa..5c9a306 100644 --- a/src/uml_device.c +++ b/src/uml_device.c @@ -46,10 +46,10 @@ static uint64_t device_total_out = 0; enum request_type { REQ_NEW_CONTROL }; static struct request { - uint32_t magic; - uint32_t version; - enum request_type type; - struct sockaddr_un sock; + uint32_t magic; + uint32_t version; + enum request_type type; + struct sockaddr_un sock; } request; static struct sockaddr_un data_sun; @@ -64,8 +64,9 @@ static bool setup_device(void) { } name; struct timeval tv; - if(!get_config_string(lookup_config(config_tree, "Device"), &device)) + if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { xasprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname); + } get_config_string(lookup_config(config_tree, "Interface"), &iface); @@ -113,7 +114,7 @@ static bool setup_device(void) { name.usecs = tv.tv_usec; data_sun.sun_family = AF_UNIX; memcpy(&data_sun.sun_path, &name, sizeof(name)); - + if(bind(data_fd, (struct sockaddr *)&data_sun, sizeof(data_sun)) < 0) { logger(LOG_ERR, "Could not bind data %s: %s", device_info, strerror(errno)); running = false; @@ -122,7 +123,7 @@ static bool setup_device(void) { if((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { logger(LOG_ERR, "Could not open %s: %s", device_info, - strerror(errno)); + strerror(errno)); return false; } @@ -139,6 +140,7 @@ static bool setup_device(void) { listen_sun.sun_family = AF_UNIX; strncpy(listen_sun.sun_path, device, sizeof(listen_sun.sun_path)); + if(bind(listen_fd, (struct sockaddr *)&listen_sun, sizeof(listen_sun)) < 0) { logger(LOG_ERR, "Could not bind %s to %s: %s", device_info, device, strerror(errno)); return false; @@ -154,126 +156,135 @@ static bool setup_device(void) { logger(LOG_INFO, "%s is a %s", device, device_info); - if(routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { overwrite_mac = true; + } return true; } void close_device(void) { - if(listen_fd >= 0) + if(listen_fd >= 0) { close(listen_fd); + } - if(request_fd >= 0) + if(request_fd >= 0) { close(request_fd); + } - if(data_fd >= 0) + if(data_fd >= 0) { close(data_fd); + } - if(write_fd >= 0) + if(write_fd >= 0) { close(write_fd); + } unlink(device); free(device); - if(iface) free(iface); + + if(iface) { + free(iface); + } } static bool read_packet(vpn_packet_t *packet) { int lenin; switch(state) { - case 0: { - struct sockaddr sa; - socklen_t salen = sizeof(sa); + case 0: { + struct sockaddr sa; + socklen_t salen = sizeof(sa); + + request_fd = accept(listen_fd, &sa, &salen); - request_fd = accept(listen_fd, &sa, &salen); - if(request_fd < 0) { - logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno)); - return false; - } + if(request_fd < 0) { + logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno)); + return false; + } #ifdef FD_CLOEXEC - fcntl(request_fd, F_SETFD, FD_CLOEXEC); + fcntl(request_fd, F_SETFD, FD_CLOEXEC); #endif - if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) { - logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno)); - running = false; - return false; - } + if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) { + logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno)); + running = false; + return false; + } + + close(listen_fd); + listen_fd = -1; + device_fd = request_fd; + state = 1; - close(listen_fd); - listen_fd = -1; - device_fd = request_fd; - state = 1; + return false; + } + case 1: { + if((lenin = read(request_fd, &request, sizeof(request))) != sizeof request) { + logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info, + device, strerror(errno)); + running = false; return false; } - case 1: { - if((lenin = read(request_fd, &request, sizeof(request))) != sizeof request) { - logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info, - device, strerror(errno)); - running = false; - return false; - } - - if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) { - logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s", - request.magic, request.version, request.type, device_info, device); - running = false; - return false; - } - - if(connect(write_fd, &request.sock, sizeof(request.sock)) < 0) { - logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno)); - running = false; - return false; - } - - write(request_fd, &data_sun, sizeof(data_sun)); - device_fd = data_fd; - - logger(LOG_INFO, "Connection with UML established"); - - state = 2; + if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) { + logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s", + request.magic, request.version, request.type, device_info, device); + running = false; return false; } - case 2: { - if((lenin = read(data_fd, packet->data, MTU)) <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); - running = false; - return false; - } + if(connect(write_fd, &request.sock, sizeof(request.sock)) < 0) { + logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno)); + running = false; + return false; + } - packet->len = lenin; + write(request_fd, &data_sun, sizeof(data_sun)); + device_fd = data_fd; - device_total_in += packet->len; + logger(LOG_INFO, "Connection with UML established"); - ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, - device_info); + state = 2; + return false; + } - return true; + case 2: { + if((lenin = read(data_fd, packet->data, MTU)) <= 0) { + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); + running = false; + return false; } - default: - logger(LOG_ERR, "Invalid value for state variable in " FILE); - abort(); + packet->len = lenin; + + device_total_in += packet->len; + + ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, + device_info); + + return true; + } + + default: + logger(LOG_ERR, "Invalid value for state variable in " FILE); + abort(); } } static bool write_packet(vpn_packet_t *packet) { if(state != 2) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet", - packet->len, device_info); + packet->len, device_info); return false; } ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); + packet->len, device_info); if(write(write_fd, packet->data, packet->len) < 0) { if(errno != EINTR && errno != EAGAIN) { diff --git a/src/utils.c b/src/utils.c index 656f1ea..70a5c99 100644 --- a/src/utils.c +++ b/src/utils.c @@ -26,23 +26,28 @@ static const char hexadecimals[] = "0123456789ABCDEF"; static int charhex2bin(char c) { - if(isdigit(c)) + if(isdigit(c)) { return c - '0'; - else + } else { return toupper(c) - 'A' + 10; + } } bool hex2bin(char *src, char *dst, int length) { for(int i = 0; i < length; i++) { - if(!isxdigit(src[i * 2]) || !isxdigit(src[i * 2 + 1])) + if(!isxdigit(src[i * 2]) || !isxdigit(src[i * 2 + 1])) { return false; + } + dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]); } + return true; } void bin2hex(char *src, char *dst, int length) { int i; + for(i = length - 1; i >= 0; i--) { dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15]; dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4]; @@ -59,13 +64,14 @@ const char *winerror(int err) { ptr = buf + sprintf(buf, "(%d) ", err); - if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), ptr, sizeof(buf) - (ptr - buf), NULL)) { + if(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), ptr, sizeof(buf) - (ptr - buf), NULL)) { strcpy(ptr, "(unable to format errormessage)"); }; - if((ptr = strchr(buf, '\r'))) + if((ptr = strchr(buf, '\r'))) { *ptr = '\0'; + } return buf; } @@ -73,8 +79,11 @@ const char *winerror(int err) { unsigned int bitfield_to_int(const void *bitfield, size_t size) { unsigned int value = 0; - if(size > sizeof(value)) + + if(size > sizeof(value)) { size = sizeof(value); + } + memcpy(&value, bitfield, size); return value; } @@ -83,13 +92,14 @@ unsigned int bitfield_to_int(const void *bitfield, size_t size) { * As memcmp(), but constant-time. * Returns 0 when data is equal, non-zero otherwise. */ -int memcmp_constant_time (const void *a, const void *b, size_t size) { - const uint8_t *a1 = a, *b1 = b; - int ret = 0; - size_t i; +int memcmp_constant_time(const void *a, const void *b, size_t size) { + const uint8_t *a1 = a, *b1 = b; + int ret = 0; + size_t i; - for (i = 0; i < size; i++) - ret |= *a1++ ^ *b1++; + for(i = 0; i < size; i++) { + ret |= *a1++ ^ *b1++; + } - return ret; + return ret; } diff --git a/src/utils.h b/src/utils.h index b598700..fbeae5e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -42,6 +42,6 @@ extern const char *winerror(int); extern unsigned int bitfield_to_int(const void *bitfield, size_t size); -int memcmp_constant_time (const void *a, const void *b, size_t size); +int memcmp_constant_time(const void *a, const void *b, size_t size); #endif diff --git a/src/vde_device.c b/src/vde_device.c index e69ae80..d97a694 100644 --- a/src/vde_device.c +++ b/src/vde_device.c @@ -49,8 +49,9 @@ static bool setup_device(void) { return false; } - if(!get_config_string(lookup_config(config_tree, "Device"), &device)) + if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { xasprintf(&device, LOCALSTATEDIR "/run/vde.ctl"); + } get_config_string(lookup_config(config_tree, "Interface"), &iface); @@ -67,6 +68,7 @@ static bool setup_device(void) { }; conn = plug.vde_open(device, identname, &args); + if(!conn) { logger(LOG_ERR, "Could not open VDE socket %s", device); return false; @@ -80,18 +82,21 @@ static bool setup_device(void) { logger(LOG_INFO, "%s is a %s", device, device_info); - if(routing_mode == RMODE_ROUTER) + if(routing_mode == RMODE_ROUTER) { overwrite_mac = true; + } return true; } static void close_device(void) { - if(conn) + if(conn) { plug.vde_close(conn); + } - if(plug.dl_handle) + if(plug.dl_handle) { libvdeplug_dynclose(plug); + } free(device); @@ -100,6 +105,7 @@ static void close_device(void) { static bool read_packet(vpn_packet_t *packet) { int lenin = (ssize_t)plug.vde_recv(conn, packet->data, MTU, 0); + if(lenin <= 0) { logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); running = false; diff --git a/src/xalloc.h b/src/xalloc.h index 9d3a71e..0eecda5 100644 --- a/src/xalloc.h +++ b/src/xalloc.h @@ -21,34 +21,46 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -static inline void *xmalloc(size_t n) __attribute__ ((__malloc__)); +static inline void *xmalloc(size_t n) __attribute__((__malloc__)); static inline void *xmalloc(size_t n) { void *p = malloc(n); - if(!p) + + if(!p) { abort(); + } + return p; } -static inline void *xmalloc_and_zero(size_t n) __attribute__ ((__malloc__)); +static inline void *xmalloc_and_zero(size_t n) __attribute__((__malloc__)); static inline void *xmalloc_and_zero(size_t n) { void *p = calloc(1, n); - if(!p) + + if(!p) { abort(); + } + return p; } static inline void *xrealloc(void *p, size_t n) { p = realloc(p, n); - if(!p) + + if(!p) { abort(); + } + return p; } -static inline char *xstrdup(const char *s) __attribute__ ((__malloc__)); +static inline char *xstrdup(const char *s) __attribute__((__malloc__)); static inline char *xstrdup(const char *s) { char *p = strdup(s); - if(!p) + + if(!p) { abort(); + } + return p; } @@ -56,18 +68,24 @@ static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { #ifdef HAVE_MINGW char buf[1024]; int result = vsnprintf(buf, sizeof(buf), fmt, ap); - if(result < 0) + + if(result < 0) { abort(); + } + *strp = xstrdup(buf); #else int result = vasprintf(strp, fmt, ap); - if(result < 0) + + if(result < 0) { abort(); + } + #endif return result; } -static inline int xasprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__(printf, 2, 3))); +static inline int xasprintf(char **strp, const char *fmt, ...) __attribute__((__format__(printf, 2, 3))); static inline int xasprintf(char **strp, const char *fmt, ...) { va_list ap; va_start(ap, fmt);