+
+ return -1;
+}
+
+/* VPN packet I/O */
+
+static void receive_packet(node_t *n, vpn_packet_t *packet) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
+ packet->len, n->name, n->hostname);
+
+ n->in_packets++;
+ n->in_bytes += packet->len;
+
+ route(n, packet);
+}
+
+static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
+ if(n->status.sptps)
+ return sptps_verify_datagram(&n->sptps, DATA(inpkt), inpkt->len);
+
+#ifdef DISABLE_LEGACY
+ return false;
+#else
+ if(!n->status.validkey_in || !digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
+ return false;
+
+ return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
+#endif
+}
+
+static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
+ vpn_packet_t pkt1, pkt2;
+ vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
+ int nextpkt = 0;
+ size_t outlen;
+ pkt1.offset = DEFAULT_PACKET_OFFSET;
+ pkt2.offset = DEFAULT_PACKET_OFFSET;
+
+ if(n->status.sptps) {
+ if(!n->sptps.state) {
+ if(!n->status.waitingforkey) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but we haven't exchanged keys yet", n->name, n->hostname);
+ send_req_key(n);
+ } else {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
+ }
+ return false;
+ }
+ inpkt->offset += 2 * sizeof(node_id_t);
+ n->status.udppacket = true;
+ bool result = sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t));
+ n->status.udppacket = false;
+
+ if(!result) {
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
+ return false;
+ }
+ return true;
+ }
+
+#ifdef DISABLE_LEGACY
+ return false;
+#else
+ if(!n->status.validkey_in) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
+ return false;
+ }
+
+ /* Check packet length */
+
+ if(inpkt->len < sizeof(seqno_t) + digest_length(n->indigest)) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
+ n->name, n->hostname);
+ return false;
+ }
+
+ /* It's a legacy UDP packet, the data starts after the seqno */
+
+ inpkt->offset += sizeof(seqno_t);
+
+ /* Check the message authentication code */
+
+ if(digest_active(n->indigest)) {
+ inpkt->len -= digest_length(n->indigest);
+ if(!digest_verify(n->indigest, SEQNO(inpkt), inpkt->len, SEQNO(inpkt) + inpkt->len)) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
+ return false;
+ }
+ }
+ /* Decrypt the packet */
+
+ if(cipher_active(n->incipher)) {
+ vpn_packet_t *outpkt = pkt[nextpkt++];
+ outlen = MAXSIZE;
+
+ if(!cipher_decrypt(n->incipher, SEQNO(inpkt), inpkt->len, SEQNO(outpkt), &outlen, true)) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
+ return false;
+ }
+
+ outpkt->len = outlen;
+ inpkt = outpkt;
+ }
+
+ /* Check the sequence number */
+
+ seqno_t seqno;
+ memcpy(&seqno, SEQNO(inpkt), sizeof seqno);
+ seqno = ntohl(seqno);
+ inpkt->len -= sizeof seqno;
+
+ if(replaywin) {
+ if(seqno != n->received_seqno + 1) {
+ if(seqno >= n->received_seqno + replaywin * 8) {
+ if(n->farfuture++ < replaywin >> 2) {
+ logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
+ n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
+ return false;
+ }
+ logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
+ seqno - n->received_seqno - 1, n->name, n->hostname);
+ memset(n->late, 0, replaywin);
+ } else if (seqno <= n->received_seqno) {
+ if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) {
+ logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
+ n->name, n->hostname, seqno, n->received_seqno);
+ return false;
+ }
+ } else {
+ for(int i = n->received_seqno + 1; i < seqno; i++)
+ n->late[(i / 8) % replaywin] |= 1 << i % 8;
+ }
+ }
+
+ n->farfuture = 0;
+ n->late[(seqno / 8) % replaywin] &= ~(1 << seqno % 8);
+ }
+
+ if(seqno > n->received_seqno)
+ n->received_seqno = seqno;
+
+ n->received++;
+
+ if(n->received_seqno > MAX_SEQNO)
+ regenerate_key();
+
+ /* Decompress the packet */
+
+ length_t origlen = inpkt->len;
+
+ if(n->incompression) {
+ vpn_packet_t *outpkt = pkt[nextpkt++];
+
+ if((outpkt->len = uncompress_packet(DATA(outpkt), DATA(inpkt), inpkt->len, n->incompression)) < 0) {
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
+ n->name, n->hostname);
+ return false;
+ }
+
+ inpkt = outpkt;
+
+ origlen -= MTU/64 + 20;
+ }
+
+ if(inpkt->len > n->maxrecentlen)
+ n->maxrecentlen = inpkt->len;
+
+ inpkt->priority = 0;
+
+ if(!DATA(inpkt)[12] && !DATA(inpkt)[13])
+ udp_probe_h(n, inpkt, origlen);
+ else
+ receive_packet(n, inpkt);
+ return true;