X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fnet_packet.c;h=ac63f62803e53cf11a6b5568c54ba5cc9995c08a;hb=742f7bb04e72d93f2c4a858534144a599b3fc14d;hp=cbdc15cfebc98ea77156017b65db2c4beb3d472a;hpb=19be9cf7150858311f7898fa3fb525d692d02f64;p=tinc diff --git a/src/net_packet.c b/src/net_packet.c index cbdc15cf..ac63f628 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -252,6 +252,9 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) { } static bool try_mac(node_t *n, const vpn_packet_t *inpkt) { + if(n->status.sptps) + return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len); + if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) return false; @@ -265,6 +268,11 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { vpn_packet_t *outpkt = pkt[0]; size_t outlen; + if(n->status.sptps) { + sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len); + return; + } + if(!cipher_active(&n->incipher)) { logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname); @@ -380,6 +388,42 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) { receive_packet(c->node, &outpkt); } +static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) { + if(n->status.sptps) { + uint8_t type = 0; + int offset = 0; + + if(!(origpkt->data[12] | origpkt->data[13])) { + sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len); + return; + } + + if(routing_mode == RMODE_ROUTER) + offset = 14; + else + type = PKT_MAC; + + if(origpkt->len < offset) + return; + + vpn_packet_t outpkt; + + if(n->outcompression) { + int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression); + if(len < 0) { + logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname); + } else if(len < origpkt->len - offset) { + outpkt.len = len + offset; + origpkt = &outpkt; + type |= PKT_COMPRESSED; + } + } + + sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset); + return; + } +} + static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { vpn_packet_t pkt1, pkt2; vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 }; @@ -390,14 +434,17 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { size_t outlen; #if defined(SOL_IP) && defined(IP_TOS) static int priority = 0; - int origpriority = origpkt->priority; #endif + int origpriority = origpkt->priority; if(!n->status.reachable) { logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname); return; } + if(n->status.sptps) + return send_sptps_packet(n, origpkt); + /* Make sure we have a valid key */ if(!n->status.validkey) { @@ -531,6 +578,117 @@ end: origpkt->len = origlen; } +bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) { + node_t *to = handle; + + if(type >= SPTPS_HANDSHAKE || ((myself->options | to->options) & OPTION_TCPONLY)) { + char buf[len * 4 / 3 + 5]; + b64encode(data, buf, len); + if(!to->status.validkey) + return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, myself->name, to->name, buf, myself->incompression); + else + return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_SPTPS, buf); + } + + /* Send the packet */ + + struct sockaddr *sa; + socklen_t sl; + int sock; + + sa = &(to->address.sa); + sl = SALEN(to->address.sa); + sock = to->sock; + + if(sendto(listen_socket[sock].udp, data, len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) { + if(sockmsgsize(sockerrno)) { + if(to->maxmtu >= len) + to->maxmtu = len - 1; + if(to->mtu >= len) + to->mtu = len - 1; + } else { + logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", to->name, to->hostname, sockstrerror(sockerrno)); + return false; + } + } + + return true; +} + +bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len) { + node_t *from = handle; + + if(type == SPTPS_HANDSHAKE) { + from->status.validkey = true; + logger(DEBUG_META, LOG_INFO, "SPTPS key exchange with %s (%s) succesful", from->name, from->hostname); + return true; + } + + if(len > MTU) { + logger(DEBUG_ALWAYS, LOG_ERR, "Packet from %s (%s) larger than maximum supported size (%d > %d)", from->name, from->hostname, len, MTU); + return false; + } + + vpn_packet_t inpkt; + + if(type == PKT_PROBE) { + inpkt.len = len; + memcpy(inpkt.data, data, len); + mtu_probe_h(from, &inpkt, len); + return true; + } + + if(type & ~(PKT_COMPRESSED | PKT_MAC)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Unexpected SPTPS record type %d len %d from %s (%s)", type, len, from->name, from->hostname); + return false; + } + + /* Check if we have the headers we need */ + if(routing_mode != RMODE_ROUTER && !(type & PKT_MAC)) { + logger(DEBUG_TRAFFIC, LOG_ERR, "Received packet from %s (%s) without MAC header (maybe Mode is not set correctly)", from->name, from->hostname); + return false; + } else if(routing_mode == RMODE_ROUTER && (type & PKT_MAC)) { + logger(DEBUG_TRAFFIC, LOG_WARNING, "Received packet from %s (%s) with MAC header (maybe Mode is not set correctly)", from->name, from->hostname); + } + + int offset = (type & PKT_MAC) ? 0 : 14; + if(type & PKT_COMPRESSED) { + len = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression); + if(len < 0) { + return false; + } else { + inpkt.len = len + offset; + } + if(inpkt.len > MAXSIZE) + abort(); + } else { + memcpy(inpkt.data + offset, data, len); + inpkt.len = len + offset; + } + + /* Generate the Ethernet packet type if necessary */ + if(offset) { + switch(inpkt.data[14] >> 4) { + case 4: + inpkt.data[12] = 0x08; + inpkt.data[13] = 0x00; + break; + case 6: + inpkt.data[12] = 0x86; + inpkt.data[13] = 0xDD; + break; + default: + logger(DEBUG_TRAFFIC, LOG_ERR, + "Unknown IP version %d while reading packet from %s (%s)", + inpkt.data[14] >> 4, from->name, from->hostname); + return false; + } + } + + receive_packet(from, &inpkt); + return true; +} + /* send a packet to the given vpn ip. */ @@ -558,6 +716,11 @@ void send_packet(node_t *n, vpn_packet_t *packet) { n->out_packets++; n->out_bytes += packet->len; + if(n->status.sptps) { + send_sptps_packet(n, packet); + return; + } + via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via; if(via != n)