return;
}
+ /* The packet is supposed to come from the originator or its static relay
+ (i.e. with no dynamic relays in between).
+ If it did not, "help" the static relay by sending it UDP info.
+ Note that we only do this if we're the destination or the static relay;
+ otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
+
+ if(n != from->via && to->via == myself)
+ send_udp_info(myself, from);
+
+ /* If we're not the final recipient, relay the packet. */
+
if(to != myself) {
send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
try_tx_sptps(n, true);
add_subnet_h, del_subnet_h,
add_edge_h, del_edge_h,
key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h,
+ NULL, NULL, NULL, /* Not "real" requests (yet) */
+ udp_info_h,
};
/* Request names */
"PING", "PONG",
"ADD_SUBNET", "DEL_SUBNET",
"ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
+ "REQ_PUBKEY", "ANS_PUBKEY", "REQ_SPTPS", "UDP_INFO",
};
static splay_tree_t *past_request_tree;
/* Protocol version. Different major versions are incompatible. */
#define PROT_MAJOR 17
-#define PROT_MINOR 4 /* Should not exceed 255! */
+#define PROT_MINOR 5 /* Should not exceed 255! */
/* Silly Windows */
CONTROL,
REQ_PUBKEY, ANS_PUBKEY,
REQ_SPTPS,
+ UDP_INFO,
LAST /* Guardian for the highest request number */
} request_t;
extern bool send_req_key(struct node_t *);
extern bool send_ans_key(struct node_t *);
extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *);
+extern bool send_udp_info(struct node_t *, struct node_t *);
/* Request handlers */
extern bool ans_key_h(struct connection_t *, const char *);
extern bool tcppacket_h(struct connection_t *, const char *);
extern bool control_h(struct connection_t *, const char *);
+extern bool udp_info_h(struct connection_t *, const char *);
#endif /* __TINC_PROTOCOL_H__ */
#include "netutl.h"
#include "protocol.h"
#include "utils.h"
+#include "xalloc.h"
int maxoutbufsize = 0;
return true;
}
+
+/* Transmitting UDP information */
+
+bool send_udp_info(node_t *from, node_t *to) {
+ /* If there's a static relay in the path, there's no point in sending the message
+ farther than the static relay. */
+ to = (to->via == myself) ? to->nexthop : to->via;
+
+ /* Skip cases where sending UDP info messages doesn't make sense.
+ This is done here in order to avoid repeating the same logic in multiple callsites. */
+
+ if(to == myself)
+ return true;
+
+ if(!to->status.reachable)
+ return true;
+
+ if(from == myself && to->connection)
+ return true;
+
+ if((myself->options | from->options | to->options) & OPTION_TCPONLY)
+ return true;
+
+ if((to->nexthop->options >> 24) < 5)
+ return true;
+
+ char *from_address, *from_port;
+ /* If we're the originator, the address we use is irrelevant
+ because the first intermediate node will ignore it.
+ We use our local address as it somewhat makes sense
+ and it's simpler than introducing an encoding for "null" addresses anyway. */
+ sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port);
+
+ bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port);
+
+ free(from_address);
+ free(from_port);
+
+ return x;
+}
+
+bool udp_info_h(connection_t *c, const char* request) {
+ char from_name[MAX_STRING_SIZE];
+ char to_name[MAX_STRING_SIZE];
+ char from_address[MAX_STRING_SIZE];
+ char from_port[MAX_STRING_SIZE];
+
+ if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname);
+ return false;
+ }
+
+ if(!check_id(from_name) || !check_id(to_name)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name");
+ return false;
+ }
+
+ node_t *from = lookup_node(from_name);
+ if(!from) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, from_name);
+ return true;
+ }
+
+ if(from != from->via) {
+ /* Not supposed to happen, as it means the message wandered past a static relay */
+ logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname);
+ return true;
+ }
+
+ /* If we have a direct edge to "from", we are in a better position
+ to guess its address than it is itself. */
+ if(!from->connection && !from->status.udp_confirmed) {
+ sockaddr_t from_addr = str2sockaddr(from_address, from_port);
+ if(sockaddrcmp(&from_addr, &from->address))
+ update_node_udp(from, &from_addr);
+ }
+
+ node_t *to = lookup_node(to_name);
+ if(!to) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, to_name);
+ return true;
+ }
+
+ /* Send our own data (which could be what we just received) up the chain. */
+
+ return send_udp_info(from, to);
+}