diff --git a/src/clientmgr.c b/src/clientmgr.c index 3d322c7..e50bdb7 100644 --- a/src/clientmgr.c +++ b/src/clientmgr.c @@ -325,11 +325,13 @@ const char *state_str(enum ip_state state) { void client_ip_set_state(clientmgr_ctx *ctx, struct client *client, struct client_ip *ip, enum ip_state state) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + bool nop = false; switch (ip->state) { case IP_INACTIVE: switch (state) { case IP_INACTIVE: + nop = true; // ignore break; case IP_ACTIVE: @@ -348,12 +350,11 @@ void client_ip_set_state(clientmgr_ctx *ctx, struct client *client, struct clien client_remove_route(ctx, client, ip); break; case IP_ACTIVE: + nop = true; ip->timestamp = now; break; case IP_TENTATIVE: ip->timestamp = now; - // TODO: are we shure we want to do this just yet? - client_remove_route(ctx, client, ip); break; } break; @@ -368,17 +369,17 @@ void client_ip_set_state(clientmgr_ctx *ctx, struct client *client, struct clien client_add_route(ctx, client, ip); break; case IP_TENTATIVE: + nop = true; ip->timestamp = now; break; } break; } - char ip_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &ip->addr, ip_str, INET6_ADDRSTRLEN); - - printf("%s changes from %s to %s\n", ip_str, state_str(ip->state), - state_str(state)); + if (!nop || l3ctx.debug) { + print_ip(&ip->addr); + printf("changes from %s to %s\n", state_str(ip->state), state_str(state)); + } ip->state = state; } @@ -404,7 +405,7 @@ bool clientmgr_is_ipv4(clientmgr_ctx *ctx, struct in6_addr *address) { /** Remove an address from a client identified by its MAC. **/ void clientmgr_remove_address(clientmgr_ctx *ctx, struct in6_addr *address, uint8_t *mac, unsigned int ifindex) { - printf("TODO: clientmgr_remove_address - currently not implemented\n"); + fprintf(stderr, "TODO: clientmgr_remove_address - currently not implemented\n"); } /** Add a new address to a client identified by its MAC. @@ -412,9 +413,17 @@ void clientmgr_remove_address(clientmgr_ctx *ctx, struct in6_addr *address, uint void clientmgr_add_address(clientmgr_ctx *ctx, struct in6_addr *address, uint8_t *mac, unsigned int ifindex) { char str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, address, str, INET6_ADDRSTRLEN); - printf("clientmgr_add_address: %s\n",str); - if (!clientmgr_valid_address(ctx, address)) + + if (l3ctx.debug) + printf("clientmgr_add_address: %s is running",str); + + if (!clientmgr_valid_address(ctx, address)) { + if (l3ctx.debug) + printf(" but address is not within a client-prefix\n"); return; + } + printf("\n"); + struct client *client = get_or_create_client(ctx, mac); struct client_ip *ip = get_client_ip(client, address); @@ -423,7 +432,7 @@ void clientmgr_add_address(clientmgr_ctx *ctx, struct in6_addr *address, uint8_t bool ip_is_new = ip == NULL; if (ip_is_new) { - printf("Address: %s to client %02x:%02x:%02x:%02x:%02x:%02x\n", str, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + printf("ADDING Address: %s to client %02x:%02x:%02x:%02x:%02x:%02x\n", str, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); struct client_ip _ip = {}; memcpy(&_ip.addr, address, sizeof(struct in6_addr)); VECTOR_ADD(client->addresses, _ip); @@ -474,7 +483,7 @@ void clientmgr_notify_mac(clientmgr_ctx *ctx, uint8_t *mac, unsigned int ifindex icmp6_send_solicitation(CTX(icmp6), &address); } -/** Handle info request. +/** Handle claim (info request). */ void clientmgr_handle_claim(clientmgr_ctx *ctx, const struct in6_addr *sender, uint8_t mac[6]) { struct client *client = get_client(ctx, mac); @@ -492,13 +501,13 @@ void clientmgr_handle_claim(clientmgr_ctx *ctx, const struct in6_addr *sender, u if (!client_is_active(client)) return; - printf("Dropping client in response to claim\n"); + printf("Dropping client %02x:%02x:%02x:%02x:%02x:%02x in response to claim\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); for (int i = 0; i < VECTOR_LEN(client->addresses); i++) { struct client_ip *ip = &VECTOR_INDEX(client->addresses, i); if (ip->state == IP_ACTIVE || ip->state == IP_TENTATIVE) - client_ip_set_state(ctx, client, ip, IP_TENTATIVE); + client_ip_set_state(ctx, client, ip, IP_INACTIVE); } } @@ -507,6 +516,10 @@ void clientmgr_handle_claim(clientmgr_ctx *ctx, const struct in6_addr *sender, u */ void clientmgr_handle_info(clientmgr_ctx *ctx, struct client *foreign_client, bool relinquished) { struct client *client = get_client(ctx, foreign_client->mac); + if (l3ctx.debug) { + printf("handling info message in clientmgr_handle_info() for foreign_client"); + print_client(foreign_client); + } if (client == NULL || !client_is_active(client)) return; @@ -528,7 +541,8 @@ void clientmgr_handle_info(clientmgr_ctx *ctx, struct client *foreign_client, bo if (relinquished) add_special_ip(ctx, client); - printf("Merged "); + printf("Client info merged "); print_client(client); + printf("\n"); } diff --git a/src/clientmgr.h b/src/clientmgr.h index 6516065..5e899f5 100644 --- a/src/clientmgr.h +++ b/src/clientmgr.h @@ -24,12 +24,14 @@ struct client_ip { struct timespec timestamp; }; -struct client { +typedef struct client { unsigned int ifindex; struct timespec timeout; uint8_t mac[6]; VECTOR(struct client_ip) addresses; -}; +} client_t; + + typedef struct { struct l3ctx *l3ctx; diff --git a/src/intercom.c b/src/intercom.c index 9d134b5..0ea6989 100644 --- a/src/intercom.c +++ b/src/intercom.c @@ -4,6 +4,10 @@ #include "if.h" #include "icmp6.h" #include "syscallwrappers.h" +#include "util.h" + +//TODO this is used for print_client - remove +#include "clientmgr.h" #include #include @@ -17,6 +21,13 @@ #define INTERCOM_GROUP "ff02::5523" #define INTERCOM_MAX_RECENT 100 +#define CLAIM_RETRY_MAX 5 + +// Announce at most 32 addresses per client +#define INFO_MAX 32 + +void schedule_claim_retry(struct claim_task*); + bool join_mcast(const int sock, const struct in6_addr addr, intercom_if *iface) { struct ipv6_mreq mreq; @@ -132,9 +143,12 @@ bool intercom_send_packet_unicast(intercom_ctx *ctx, const struct in6_addr *reci .sin6_port = htons(INTERCOM_PORT), .sin6_addr = *recipient }; - ssize_t rc = sendto(ctx->fd, packet, packet_len, 0, (struct sockaddr*)&addr, sizeof(addr)); - + if (l3ctx.debug) { + printf("sent intercom packet rc: %zi to ", rc); + print_ip(recipient); + printf("\n"); + } if (rc < 0) perror("sendto failed"); @@ -153,7 +167,8 @@ void intercom_send_packet(intercom_ctx *ctx, uint8_t *packet, ssize_t packet_len groupaddr.sin6_scope_id = iface->ifindex; ssize_t rc = sendto(ctx->fd, packet, packet_len, 0, (struct sockaddr*)&groupaddr, sizeof(groupaddr)); - printf("sent packet to %s on iface %s rc: %zi\n", INTERCOM_GROUP, iface->ifname,rc); + if (l3ctx.debug) + printf("sent intercom packet to %s on iface %s rc: %zi\n", INTERCOM_GROUP, iface->ifname,rc); if (rc < 0) iface->ok = false; @@ -192,6 +207,29 @@ void intercom_handle_claim(intercom_ctx *ctx, intercom_packet_claim *packet) { clientmgr_handle_claim(CTX(clientmgr), &sender, packet->mac); } + + +/** Finds the entry for a peer with a specified ID in the array \e ctx.peers */ +/* +static fastd_peer_t ** peer_p_find_by_id(uint64_t id) { + fastd_peer_t key = {.id = id}; + fastd_peer_t *const keyp = &key; + + return VECTOR_BSEARCH(&keyp, ctx.peers, peer_id_cmp); +} +*/ + +bool find_repeatable_claim(uint8_t mac[6], int *index) { + // TODO: replace this with VECTOR_BSEARCH -- see the example above + for (*index=0;*indexmac, mac, 6)) + return true; + } + return false; +} + + void intercom_handle_info(intercom_ctx *ctx, intercom_packet_info *packet) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -200,6 +238,11 @@ void intercom_handle_info(intercom_ctx *ctx, intercom_packet_info *packet) { memcpy(client.mac, &packet->mac, sizeof(uint8_t) * 6); + int i; + + if (find_repeatable_claim(packet->mac, &i)) + VECTOR_DELETE(ctx->repeatable_claims, i); + struct client_ip ip = { .state = IP_INACTIVE }; @@ -262,8 +305,6 @@ void intercom_handle_in(intercom_ctx *ctx, int fd) { } } -// Announce at most 32 addresses per client -#define INFO_MAX 32 /* recipient = NULL -> send to neighbours */ void intercom_info(intercom_ctx *ctx, const struct in6_addr *recipient, struct client *client, bool relinquished) { @@ -297,8 +338,10 @@ void intercom_info(intercom_ctx *ctx, const struct in6_addr *recipient, struct c ssize_t packet_len = sizeof(intercom_packet_info) + i * sizeof(intercom_packet_info_entry); if (recipient != NULL) + // TODO: consider adding resilience here. There *might* be an ACK sensible intercom_send_packet_unicast(ctx, recipient, (uint8_t*)packet, packet_len); else { + // forward packet to other l3roamd instances intercom_recently_seen_add(ctx, &packet->hdr); intercom_send_packet(ctx, (uint8_t*)packet, packet_len); @@ -306,6 +349,51 @@ void intercom_info(intercom_ctx *ctx, const struct in6_addr *recipient, struct c free(packet); } +void claim_retry_task(void *d) { + struct claim_task *data = d; + + int i; + if (!find_repeatable_claim(data->client->mac, &i)) + return; + + if (data->recipient != NULL) { + if (l3ctx.debug) { + printf("sending unicast claim for client %02x:%02x:%02x:%02x:%02x:%02x to ", data->client->mac[0], data->client->mac[1], data->client->mac[2], data->client->mac[3], data->client->mac[4], data->client->mac[5]); + print_ip(data->recipient); + printf("\n"); + } + intercom_send_packet_unicast(&l3ctx.intercom_ctx, data->recipient, (uint8_t*)&data->packet, sizeof(data->packet)); + } else { + if (l3ctx.debug) { + printf("sending multicast claim for client %02x:%02x:%02x:%02x:%02x:%02x\n", data->client->mac[0], data->client->mac[1], data->client->mac[2], data->client->mac[3], data->client->mac[4], data->client->mac[5]); + } + intercom_send_packet(&l3ctx.intercom_ctx, (uint8_t*)&data->packet, sizeof(data->packet)); + } + + if (data->retries_left > 0) + schedule_claim_retry(data); +} +void free_claim_task(void *d) { + struct claim_task *data = d; + free(data->client); + free(data); +} + +void schedule_claim_retry(struct claim_task *data) { + struct claim_task *ndata = calloc(1, sizeof(struct claim_task)); + ndata->client = malloc(sizeof(struct client)); + memcpy(ndata->client, data->client,sizeof(struct client)); + ndata->retries_left = data->retries_left -1; + ndata->packet = data->packet; + ndata->recipient = data->recipient; + ndata->check_task = data->check_task; + + if (data->check_task == NULL && data->retries_left > 0) + data->check_task = post_task(&l3ctx.taskqueue_ctx, 3, claim_retry_task, free_claim_task, ndata); + else + free_claim_task(ndata); +} + bool intercom_claim(intercom_ctx *ctx, const struct in6_addr *recipient, struct client *client) { intercom_packet_claim packet; uint32_t nonce; @@ -324,10 +412,17 @@ bool intercom_claim(intercom_ctx *ctx, const struct in6_addr *recipient, struct intercom_recently_seen_add(ctx, &packet.hdr); - if (recipient != NULL) - return intercom_send_packet_unicast(ctx, recipient, (uint8_t*)&packet, sizeof(packet)); - else { - intercom_send_packet(ctx, (uint8_t*)&packet, sizeof(packet)); - return true; - } + VECTOR_ADD(ctx->repeatable_claims, *client); + + struct claim_task data ; + data.client = malloc(sizeof(struct client)); + memcpy(data.client, client,sizeof(struct client)); + data.retries_left = CLAIM_RETRY_MAX; + data.packet = packet; + data.recipient = recipient; + data.check_task=NULL; + + claim_retry_task(&data); + free(data.client); + return true; } diff --git a/src/intercom.h b/src/intercom.h index 85a1d9a..ecd619e 100644 --- a/src/intercom.h +++ b/src/intercom.h @@ -2,6 +2,8 @@ #include "vector.h" #include "if.h" +#include "clientmgr.h" +#include "taskqueue.h" #include #include @@ -46,6 +48,17 @@ typedef struct { char *ifname; } intercom_if; +struct claim_task { + struct client *client; + uint8_t retries_left; + const struct in6_addr *recipient; + intercom_packet_claim packet; + taskqueue_t *check_task; +}; + +typedef struct { +} claim_t; + typedef struct { struct l3ctx *l3ctx; int fd; @@ -53,9 +66,11 @@ typedef struct { struct in6_addr ip; VECTOR(intercom_packet_hdr) recent_packets; VECTOR(intercom_if) interfaces; + VECTOR(client_t) repeatable_claims; } intercom_ctx; -struct client; + +// struct client; void intercom_recently_seen_add(intercom_ctx *ctx, intercom_packet_hdr *hdr); void intercom_send_packet(intercom_ctx *ctx, uint8_t *packet, ssize_t packet_len); diff --git a/src/ipmgr.c b/src/ipmgr.c index c2fee88..f67db40 100644 --- a/src/ipmgr.c +++ b/src/ipmgr.c @@ -80,6 +80,7 @@ bool tun_open(ipmgr_ctx *ctx, const char *ifname, uint16_t mtu, const char *dev_ /* find an entry in the ipmgr's unknown-clients list*/ struct entry *find_entry(ipmgr_ctx *ctx, const struct in6_addr *k) { + // TODO: make use of VECTOR_BSEARCH here. for (int i = 0; i < VECTOR_LEN(ctx->addrs); i++) { struct entry *e = &VECTOR_INDEX(ctx->addrs, i); if (l3ctx.debug) { @@ -126,8 +127,10 @@ void seek_address(ipmgr_ctx *ctx, struct in6_addr *addr) { data->ctx = ctx; data->address = *addr; - // TODO: Scheduling this task 1s in the future seems to be a long time. find a way to cut this time to 300ms or so. - post_task(CTX(taskqueue), 1, seek_task, free, data); + if (data->check_task == NULL) + data->check_task = post_task(CTX(taskqueue), 1, seek_task, free, data); + else + free(data); } void handle_packet(ipmgr_ctx *ctx, uint8_t packet[], ssize_t packet_len) { @@ -195,6 +198,8 @@ void schedule_ipcheck(ipmgr_ctx *ctx, struct entry *e) { if (e->check_task == NULL) e->check_task = post_task(CTX(taskqueue), IPCHECK_INTERVAL, ipcheck_task, free, data); + else + free(data); } void seek_task(void *d) { @@ -203,7 +208,7 @@ void seek_task(void *d) { if (!e) { if (l3ctx.debug) { - printf("INFO: seek task was scheduled but no remaining packets available for host:"); + printf("INFO: seek task was scheduled but no remaining packets available for host: "); print_ip(&data->address); } return; @@ -212,7 +217,7 @@ void seek_task(void *d) { if (!clientmgr_is_known_address(&l3ctx.clientmgr_ctx, &data->address)) { if (l3ctx.debug) { - printf("seeking on intercom for client"); + printf("seeking on intercom for client "); print_ip(&data->address); } intercom_seek(&l3ctx.intercom_ctx, (const struct in6_addr*) &(data->address)); @@ -224,17 +229,20 @@ void ipcheck_task(void *d) { struct entry *e = find_entry(data->ctx, &data->address); - if (!e) + if (!e) { return; + } char str[INET6_ADDRSTRLEN] = ""; inet_ntop(AF_INET6, &data->address, str, sizeof str); - printf("running an ipcheck on %s\n", str); + if (l3ctx.debug) + printf("running an ipcheck on %s\n", str); e->check_task = NULL; - if (ipcheck(data->ctx, e)) + if (ipcheck(data->ctx, e)) { schedule_ipcheck(data->ctx, e); + } } bool ipcheck(ipmgr_ctx *ctx, struct entry *e) { @@ -248,8 +256,10 @@ bool ipcheck(ipmgr_ctx *ctx, struct entry *e) { struct packet *p = VECTOR_INDEX(e->packets, i); if (timespec_cmp(p->timestamp, then) <= 0) { + if (l3ctx.debug) + printf("deleting old packet\n"); free(p->data); - printf("deleting old packet"); + free(p); VECTOR_DELETE(e->packets, i); i--; } @@ -301,6 +311,7 @@ void ipmgr_handle_in(ipmgr_ctx *ctx, int fd) { void ipmgr_handle_out(ipmgr_ctx *ctx, int fd) { ssize_t count; + while (1) { if (VECTOR_LEN(ctx->output_queue) == 0) break; diff --git a/src/ipmgr.h b/src/ipmgr.h index 4c7423d..6004c5a 100644 --- a/src/ipmgr.h +++ b/src/ipmgr.h @@ -65,6 +65,7 @@ typedef struct { struct ip_task { ipmgr_ctx *ctx; struct in6_addr address; + taskqueue_t *check_task; }; void ipmgr_init(ipmgr_ctx *ctx, char *tun_name, unsigned int mtu); diff --git a/src/main.c b/src/main.c index 4a20ea9..bdd4976 100644 --- a/src/main.c +++ b/src/main.c @@ -110,8 +110,7 @@ void loop() { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP)) { fprintf(stderr, "epoll error\n"); close(events[i].data.fd); - // TODO: routemgr is handling routes from kernel AND direct neighbours from fdb. - // Refactor this at is actually a netlink-handler + // TODO: routemgr is handling routes from kernel AND direct neighbours from fdb. Refactor this at is actually a netlink-handler } else if (l3ctx.taskqueue_ctx.fd == events[i].data.fd) { taskqueue_run(&l3ctx.taskqueue_ctx); } else if (l3ctx.routemgr_ctx.fd == events[i].data.fd) { @@ -144,9 +143,10 @@ void loop() { } void usage() { - puts("Usage: l3roamd [-h] [-b ] -a -p [-i ] -m ... -t -4 [prefix] -t "); + puts("Usage: l3roamd [-h] [-d] [-b ] -a -p [-i ] -m ... -t [-4 prefix]"); puts(" -a ip address of this node"); puts(" -b this is the bridge where all clients are connected"); + puts(" -d use debug logging"); // TODO: do we really need this? puts(" -c configuration file"); // TODO: do we really need this? puts(" -p Accept queries for this prefix. May be provided multiple times."); puts(" -s provide statistics and allow control using this socket. See below for usage instructions."); @@ -154,7 +154,6 @@ void usage() { puts(" -m mesh interface. may be specified multiple times"); puts(" -t export routes to this table"); puts(" -4 IPv4 translation prefix"); - puts(" -t interface for nat46"); puts(" -h this help\n\n"); puts("The socket will accept the following commands:"); puts("get_clients The daemon will reply with a json structure, currently providing client count."); @@ -302,8 +301,13 @@ int main(int argc, char *argv[]) { } - if (!v4_initialized) - exit_error("specifying -4 is mandatory even though it is untested and probably broken. If in doubt, use -4 0:0:0:0:0:ffff::/96"); + if (!v4_initialized) { + fprintf(stderr, "-4 was not specified. Defaulting to 0:0:0:0:0:ffff::/96"); + parse_prefix(&l3ctx.clientmgr_ctx.v4prefix, "0:0:0:0:0:ffff::/96"); + l3ctx.arp_ctx.prefix = l3ctx.clientmgr_ctx.v4prefix.prefix; + v4_initialized=true; + } + if (!a_initialized) exit_error("specifying -a is mandatory"); if (!p_initialized) diff --git a/src/routemgr.c b/src/routemgr.c index 96b8a67..0288198 100644 --- a/src/routemgr.c +++ b/src/routemgr.c @@ -59,7 +59,6 @@ int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) void rtnl_handle_neighbour(routemgr_ctx *ctx, const struct nlmsghdr *nh) { struct ndmsg *msg = NLMSG_DATA(nh); char ifname[IFNAMSIZ] = ""; - char brifname[IFNAMSIZ] = ""; struct rtattr * tb[NDA_MAX+1]; parse_rtattr(tb, NDA_MAX, NDA_RTA(msg), nh->nlmsg_len - NLMSG_LENGTH(sizeof(*msg))); @@ -70,14 +69,11 @@ void rtnl_handle_neighbour(routemgr_ctx *ctx, const struct nlmsghdr *nh) { } if_indextoname(msg->ndm_ifindex, ifname); + unsigned int br_index = if_nametoindex(ctx->client_bridge); - if (tb[NDA_MASTER]) - if_indextoname(rta_getattr_u32(tb[NDA_MASTER]),brifname); - - // FIXME use interface ids - if ( !strncmp(ctx->clientif,ifname,strlen(ifname)) || - !strncmp(ctx->client_bridge,ifname,strlen(ifname)) || - ( strlen(brifname) && !strncmp(ctx->client_bridge,brifname,strlen(brifname)) ) + if ( ctx->clientif_index == msg->ndm_ifindex || + br_index == msg->ndm_ifindex || + ( tb[NDA_MASTER] && br_index == rta_getattr_u32(tb[NDA_MASTER]) ) ) { printf("neighbour [%s] changed on interface %s, state: %i ... ", mac_str, ifname, msg->ndm_state); // see include/uapi/linux/neighbour.h NUD_REACHABLE for numeric values if (tb[NDA_MASTER]) { @@ -477,7 +473,7 @@ void rtmgr_rtnl_talk(routemgr_ctx *ctx, struct nlmsghdr *req) { int count=0; while (sendmsg(ctx->fd, &msg, 0) <= 0 && count < 5) { - printf("retrying(%i/5) ", ++count); + fprintf(stderr, "retrying(%i/5) ", ++count); perror("sendmsg on rtmgr_rtnl_talk()"); } } diff --git a/src/util.c b/src/util.c index a93ab96..d6dc2bd 100644 --- a/src/util.c +++ b/src/util.c @@ -4,7 +4,6 @@ #include #include -// TODO: where should we put this? /* print a human-readable representation of an in6_addr struct to stdout ** */ void print_ip(const struct in6_addr *addr) {