The old command was only working for ipv4 and we needed the possibility to also kill other addresses. I did throw away the old parsing by ':' and now search for the last occurrence of a colon. If a colon is found the part after the colon is parsed and checked if it is a valid port. If this is the case I check via pton if the address is v4 or v6 and fill the openvpn_sockaddr accordingly. If not I assume we have a cn.
The patch supports following kill-commands: kill ipv6:port, kill ::ffff:ipv4:port, kill ipv4:port, kill cn Signed-off-by: Stephan Kunz <stephan.k...@sophos.de> --- src/openvpn/buffer.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/buffer.h | 27 +++++++++++++++ src/openvpn/manage.c | 89 ++++++++++++++++++++++++++++++------------------- src/openvpn/manage.h | 2 +- src/openvpn/multi.c | 18 ++++------ 5 files changed, 183 insertions(+), 47 deletions(-) diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 2defd18..1c0ac81 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -828,6 +828,100 @@ buf_parse(struct buffer *buf, const int delim, char *line, const int size) } /* + * parses string for the last occurance of a given delim + */ +int +find_last_occurence_of_delim(struct buffer *buf, const int delim) +{ + bool found = false; + + int idx = buf->len; + int delim_index = 0; + + while (idx > 0 && !found) + { + delim_index = buf_read_u8_at_idx(buf, --idx); + if (delim_index == delim) + { + found = true; + } + } + + if (!found) + { + return -1; + } + + return idx; +} + +/* + * String parsing from a given index to the eol + */ +bool +buf_parse_from_idx(struct buffer *buf, const int start_idx, char *line, const int size) +{ + bool eol = false; + + int idx = start_idx; + int n = 0; + int c; + + ASSERT (size > 0); + + do + { + c = buf_read_u8_at_idx(buf, idx++); + if (c < 0) + { + eol = true; + c = 0; + } + if (n >= size) + { + break; + } + line[n++] = c; + } + while (c); + + line[size-1] = '\0'; + return !(eol && !strlen (line)); +} + +/* + * String parsing from beginning to given index + */ +bool +buf_parse_to_idx(struct buffer *buf, const int stop_idx, char *line, const int size) +{ + bool eol = false; + int n = 0; + int c; + + ASSERT (size > 0); + + do + { + c = buf_read_u8(buf); + if (c < 0) + { + eol = true; + c = 0; + } + if (n >= size) + { + break; + } + line[n++] = c; + } + while (c && buf->offset < stop_idx); + + line[buf->offset] = '\0'; + return !(eol && !strlen (line)); +} + +/* * Print a string which might be NULL */ const char * diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 28b224e..851e923 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -486,6 +486,21 @@ void convert_to_one_line(struct buffer *buf); bool buf_parse(struct buffer *buf, const int delim, char *line, const int size); /* + * Parse a string from end to beginning based on a given delimiter char + */ +bool buf_parse_from_idx (struct buffer *buf, const int start_idx, char *line, const int size); + +/* + * String parsing from beginning to given index + */ +bool buf_parse_to_idx (struct buffer *buf, const int stop_idx, char *line, const int size); + +/* + * looks for the last occurence of a given delimiter char + */ +int find_last_occurence_of_delim (struct buffer *buf, const int delim); + +/* * Hex dump -- Output a binary buffer to a hex string and return it. */ #define FHE_SPACE_BREAK_MASK 0xFF /* space_break parameter in lower 8 bits */ @@ -782,6 +797,18 @@ buf_read(struct buffer *src, void *dest, int size) } static inline int +buf_read_u8_at_idx(struct buffer *buf, int idx) +{ + int ret; + if (BLEN (buf) < 1 || BLEN (buf) < idx) + { + return -1; + } + ret = *(buf->data+idx); + return ret; +} + +static inline int buf_read_u8(struct buffer *buf) { int ret; diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 763f6c6..1ea49be 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -508,50 +508,73 @@ man_kill(struct management *man, const char *victim) if (man->persist.callback.kill_by_cn && man->persist.callback.kill_by_addr) { struct buffer buf; + struct openvpn_sockaddr saddr; char p1[128]; char p2[128]; int n_killed; + int last_delim; + bool cn = false; + int port; buf_set_read(&buf, (uint8_t *) victim, strlen(victim) + 1); - buf_parse(&buf, ':', p1, sizeof(p1)); - buf_parse(&buf, ':', p2, sizeof(p2)); + last_delim = find_last_occurence_of_delim (&buf, ':'); + if (last_delim != -1) + { + // parse from delim+1 + buf_parse_from_idx(&buf, last_delim+1, p2, sizeof (p2)); + port = atoi(p2); + // Check if port is in range + if ((strlen (p2) <= 5) && (port > 0 && port < 65536)) + { + // if port seems correct we parse for ip, need to + buf_parse_to_idx(&buf, last_delim, p1, sizeof (p1)); + } + else + { + // port seems wrong so we might have a cn here + buf_parse(&buf, -1, p1, sizeof (p1)); + cn = true; + } + } + else + { + // as we do not found a delimiter we assume we have a cn + buf_parse(&buf, -1, p1, sizeof (p1)); + cn = true; + } - if (strlen(p1) && strlen(p2)) + CLEAR (saddr); + // Check if address is v4 + if (!cn && inet_pton(AF_INET, p1, &(saddr.addr.in4.sin_addr))) { - /* IP:port specified */ - bool status; - const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, 0, &status, NULL); - if (status) + saddr.addr.in4.sin_family = AF_INET; + saddr.addr.in4.sin_port = htons(port); + } + // Check if address is v6 + else if (!cn && inet_pton(AF_INET6, p1, &(saddr.addr.in6.sin6_addr))) + { + saddr.addr.in6.sin6_family = AF_INET6; + saddr.addr.in6.sin6_port = htons(port); + } + + if (!cn) + { + n_killed = (*man->persist.callback.kill_by_addr) (man->persist.callback.arg, &saddr); + if (n_killed > 0) { - const int port = atoi(p2); - if (port > 0 && port < 65536) - { - n_killed = (*man->persist.callback.kill_by_addr)(man->persist.callback.arg, addr, port); - if (n_killed > 0) - { - msg(M_CLIENT, "SUCCESS: %d client(s) at address %s:%d killed", - n_killed, - print_in_addr_t(addr, 0, &gc), - port); - } - else - { - msg(M_CLIENT, "ERROR: client at address %s:%d not found", - print_in_addr_t(addr, 0, &gc), - port); - } - } - else - { - msg(M_CLIENT, "ERROR: port number is out of range: %s", p2); - } + msg(M_CLIENT, "SUCCESS: %d client(s) at address %s:%d killed", + n_killed, + p1, + port); } else { - msg(M_CLIENT, "ERROR: error parsing IP address: %s", p1); + msg(M_CLIENT, "ERROR: client at address %s:%d not found", + p1, + port); } } - else if (strlen(p1)) + else { /* common name specified */ n_killed = (*man->persist.callback.kill_by_cn)(man->persist.callback.arg, p1); @@ -564,10 +587,6 @@ man_kill(struct management *man, const char *victim) msg(M_CLIENT, "ERROR: common name '%s' not found", p1); } } - else - { - msg(M_CLIENT, "ERROR: kill parse"); - } } else { diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 6e5cb9b..e143e2d 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -162,7 +162,7 @@ struct management_callback void (*status) (void *arg, const int version, struct status_output *so); void (*show_net) (void *arg, const int msglevel); int (*kill_by_cn) (void *arg, const char *common_name); - int (*kill_by_addr) (void *arg, const in_addr_t addr, const int port); + int (*kill_by_addr) (void *arg, struct openvpn_sockaddr *saddr); void (*delete_event) (void *arg, event_t event); int (*n_clients) (void *arg); #ifdef MANAGEMENT_DEF_AUTH diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index f6f3f5d..93f0f6c 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3157,23 +3157,18 @@ management_callback_kill_by_cn(void *arg, const char *del_cn) } static int -management_callback_kill_by_addr(void *arg, const in_addr_t addr, const int port) +management_callback_kill_by_addr(void *arg, struct openvpn_sockaddr *saddr) { struct multi_context *m = (struct multi_context *) arg; struct hash_iterator hi; struct hash_element *he; - struct openvpn_sockaddr saddr; struct mroute_addr maddr; int count = 0; - CLEAR(saddr); - saddr.addr.in4.sin_family = AF_INET; - saddr.addr.in4.sin_addr.s_addr = htonl(addr); - saddr.addr.in4.sin_port = htons(port); - if (mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) + if (mroute_extract_openvpn_sockaddr(&maddr, saddr, true)) { - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) { struct multi_instance *mi = (struct multi_instance *) he->value; if (!mi->halt && mroute_addr_equal(&maddr, &mi->real)) @@ -3182,8 +3177,9 @@ management_callback_kill_by_addr(void *arg, const in_addr_t addr, const int port ++count; } } - hash_iterator_free(&hi); - } + hash_iterator_free (&hi); + } + return count; } -- 1.8.2.3 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel