|
|
|
@ -2,11 +2,105 @@ |
|
|
|
#include "obj.h" |
|
|
|
#include "poller.h" |
|
|
|
#include "bencode.h" |
|
|
|
#include "log.h" |
|
|
|
#include "cookie_cache.h" |
|
|
|
|
|
|
|
|
|
|
|
static void control_ng_incoming(struct obj *obj, char *buf, int len, struct sockaddr_in6 *sin, char *addr) { |
|
|
|
static void control_ng_incoming(struct obj *obj, char *buf, int buf_len, struct sockaddr_in6 *sin, char *addr) { |
|
|
|
struct control_ng *c = (void *) obj; |
|
|
|
char *data; |
|
|
|
bencode_buffer_t bencbuf; |
|
|
|
bencode_item_t *dict, *resp; |
|
|
|
char *reply; |
|
|
|
const char *cmd, *errstr, *cookie; |
|
|
|
int cmd_len, cookie_len, data_len, reply_len; |
|
|
|
struct msghdr mh; |
|
|
|
struct iovec iov[3]; |
|
|
|
|
|
|
|
data = memchr(buf, ' ', buf_len); |
|
|
|
if (!data || data == buf) { |
|
|
|
mylog(LOG_WARNING, "Received invalid data on NG port (no cookie) from %s:%u: %.*s", addr, ntohs(sin->sin6_port), buf_len, buf); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
bencode_buffer_init(&bencbuf); |
|
|
|
resp = bencode_dictionary(&bencbuf); |
|
|
|
|
|
|
|
cookie = buf; |
|
|
|
cookie_len = data - buf; |
|
|
|
*data++ = '\0'; |
|
|
|
data_len = buf_len - cookie_len - 1; |
|
|
|
|
|
|
|
errstr = "Invalid data (no payload)"; |
|
|
|
if (data_len <= 0) |
|
|
|
goto err_send; |
|
|
|
|
|
|
|
reply = cookie_cache_lookup(&c->cookie_cache, cookie); |
|
|
|
if (reply) { |
|
|
|
mylog(LOG_INFO, "Detected command from %s:%u as a duplicate", addr, ntohs(sin->sin6_port)); |
|
|
|
reply_len = strlen(reply); |
|
|
|
resp = NULL; |
|
|
|
goto send_only; |
|
|
|
} |
|
|
|
|
|
|
|
dict = bencode_decode_expect(&bencbuf, data, data_len, BENCODE_DICTIONARY); |
|
|
|
errstr = "Could not decode dictionary"; |
|
|
|
if (!dict) |
|
|
|
goto err_send; |
|
|
|
|
|
|
|
cmd = bencode_dictionary_get_string(dict, "command", &cmd_len); |
|
|
|
errstr = "Dictionary contains no key \"command\""; |
|
|
|
if (!cmd) |
|
|
|
goto err_send; |
|
|
|
|
|
|
|
mylog(LOG_INFO, "Got valid command from %s:%u: %.*s [%.*s]", addr, ntohs(sin->sin6_port), cmd_len, cmd, data_len, data); |
|
|
|
|
|
|
|
if (!strmemcmp(cmd, cmd_len, "ping")) |
|
|
|
bencode_dictionary_add_string(resp, "result", "pong"); |
|
|
|
else { |
|
|
|
errstr = "Unrecognized command"; |
|
|
|
goto err_send; |
|
|
|
} |
|
|
|
|
|
|
|
goto send_out; |
|
|
|
|
|
|
|
err_send: |
|
|
|
mylog(LOG_WARNING, "Protocol error in packet from %s:%u: %s [%.*s]", addr, ntohs(sin->sin6_port), errstr, data_len, data); |
|
|
|
bencode_dictionary_add_string(resp, "result", "error"); |
|
|
|
bencode_dictionary_add_string(resp, "error-reason", errstr); |
|
|
|
goto send_out; |
|
|
|
|
|
|
|
send_out: |
|
|
|
reply = bencode_collapse(resp, &reply_len); |
|
|
|
|
|
|
|
send_only: |
|
|
|
ZERO(mh); |
|
|
|
mh.msg_name = sin; |
|
|
|
mh.msg_namelen = sizeof(*sin); |
|
|
|
mh.msg_iov = iov; |
|
|
|
mh.msg_iovlen = 3; |
|
|
|
|
|
|
|
iov[0].iov_base = (void *) cookie; |
|
|
|
iov[0].iov_len = cookie_len; |
|
|
|
iov[1].iov_base = " "; |
|
|
|
iov[1].iov_len = 1; |
|
|
|
iov[2].iov_base = reply; |
|
|
|
iov[2].iov_len = reply_len; |
|
|
|
|
|
|
|
sendmsg(c->udp_listener.fd, &mh, 0); |
|
|
|
|
|
|
|
if (resp) |
|
|
|
cookie_cache_insert(&c->cookie_cache, cookie, reply, reply_len); |
|
|
|
|
|
|
|
goto out; |
|
|
|
|
|
|
|
cookie_cache_remove(&c->cookie_cache, cookie); |
|
|
|
out: |
|
|
|
bencode_buffer_free(&bencbuf); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct control_ng *control_ng_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) { |
|
|
|
struct control_ng *c; |
|
|
|
|
|
|
|
|