n2n/n2n.c

922 lines
25 KiB
C

/*
* (C) 2007-09 - Luca Deri <deri@ntop.org>
* Richard Andrews <andrews@ntop.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>
*
* Code contributions courtesy of:
* Richard Andrews <bbmaj7@yahoo.com.au>
* Massimo Torquati <torquati@ntop.org>
*
*/
#include "n2n.h"
#include "minilzo.h"
#include <assert.h>
#if defined(DEBUG)
# define PURGE_REGISTRATION_FREQUENCY 60
# define REGISTRATION_TIMEOUT 120
#else /* #if defined(DEBUG) */
# define PURGE_REGISTRATION_FREQUENCY 60
# define REGISTRATION_TIMEOUT (60*5)
#endif /* #if defined(DEBUG) */
char broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
char multicast_addr[6] = { 0x01, 0x00, 0x05, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */
/* ************************************** */
static void print_header( const char * msg, const struct n2n_packet_header * hdr )
{
ipstr_t buf;
ipstr_t buf2;
traceEvent(TRACE_INFO, "%s hdr: public_ip=(%d)%s:%d, private_ip=(%d)%s:%d", msg,
hdr->public_ip.family,
intoa(ntohl(hdr->public_ip.addr_type.v4_addr), buf, sizeof(buf)),
ntohs(hdr->public_ip.port),
hdr->private_ip.family,
intoa(ntohl(hdr->private_ip.addr_type.v4_addr), buf2, sizeof(buf2)),
ntohs(hdr->private_ip.port)
);
}
/* *********************************************** */
extern void sockaddr_in2peer_addr(struct sockaddr_in *in, struct peer_addr *out) {
out->family = (u_int8_t)in->sin_family;
out->port = in->sin_port;
out->addr_type.v4_addr = in->sin_addr.s_addr;
}
/* *********************************************** */
extern void peer_addr2sockaddr_in(const struct peer_addr *in, struct sockaddr_in *out) {
out->sin_family = in->family;
out->sin_port = in->port;
out->sin_addr.s_addr = in->addr_type.v4_addr;
}
/* ************************************** */
static
int marshall_peer_addr( u_int8_t * buf, size_t * offset, const struct peer_addr * s )
{
/* RA: I'm pretty sure that this is broken. There is no guarantee that the
* peer_addr structure is packed. This will always work between like hosts but
* is almost certainly broken between different host types. */
memcpy( buf + *offset, s, sizeof(struct peer_addr));
*offset += sizeof(struct peer_addr);
return sizeof(struct peer_addr); /* bytes written */
}
/* ************************************** */
static
int marshall_uint32( u_int8_t * buf, size_t * offset, u_int32_t val )
{
buf[*offset + 0] = ((val >> 24) & 0xff);
buf[*offset + 1] = ((val >> 16) & 0xff);
buf[*offset + 2] = ((val >> 8) & 0xff);
buf[*offset + 3] = ((val ) & 0xff);
*offset += 4;
return 4;
}
/* ************************************** */
int marshall_n2n_packet_header( u_int8_t * buf, const struct n2n_packet_header * hdr )
{
size_t offset = 0;
print_header( "Marshalling ", hdr );
*(buf+offset) = hdr->version;
++offset;
*(buf+offset) = hdr->msg_type;
++offset;
*(buf+offset) = hdr->ttl;
++offset;
*(buf+offset) = hdr->sent_by_supernode;
++offset;
memcpy( buf+offset, hdr->community_name, COMMUNITY_LEN );
offset += COMMUNITY_LEN;
memcpy( buf+offset, hdr->src_mac, 6 );
offset += 6;
memcpy( buf+offset, hdr->dst_mac, 6 );
offset += 6;
marshall_peer_addr( buf, &offset, &(hdr->public_ip) );
marshall_peer_addr( buf, &offset, &(hdr->private_ip) );
*(buf+offset) = (hdr->pkt_type & 0xff);
++offset;
marshall_uint32( buf, &offset, hdr->sequence_id );
marshall_uint32( buf, &offset, hdr->crc );
return offset;
}
/* ************************************** */
static
int unmarshall_peer_addr( struct peer_addr * s, size_t * offset,
const u_int8_t * buf )
{
memcpy(s, buf + *offset, sizeof(struct peer_addr));
*offset += sizeof(struct peer_addr);
return (sizeof(struct peer_addr)); /* bytes written */
}
/* ************************************** */
static
int unmarshall_uint32( u_int32_t * val, size_t * offset, const u_int8_t * buf )
{
*val = ( (buf[*offset + 0] & 0xff) << 24 );
*val |= ( (buf[*offset + 1] & 0xff) << 16 );
*val |= ( (buf[*offset + 2] & 0xff) << 8 );
*val |= ( (buf[*offset + 3] & 0xff) );
*offset += 4;
return 4;
}
/* ************************************** */
int unmarshall_n2n_packet_header( struct n2n_packet_header * hdr, const u_int8_t * buf )
{
size_t offset=0;
hdr->version = *(buf + offset);
++offset;
hdr->msg_type = *(buf + offset);
++offset;
hdr->ttl = *(buf + offset);
++offset;
hdr->sent_by_supernode = *(buf + offset);
++offset;
memcpy( hdr->community_name, (buf + offset), COMMUNITY_LEN );
offset += COMMUNITY_LEN;
memcpy( hdr->src_mac, (buf + offset), 6 );
offset += 6;
memcpy( hdr->dst_mac, (buf + offset), 6 );
offset += 6;
unmarshall_peer_addr( &(hdr->public_ip), &offset, buf );
unmarshall_peer_addr( &(hdr->private_ip), &offset, buf );
hdr->pkt_type = (*(buf + offset) & 0xff); /* Make sure only 8 bits are copied. */
++offset;
unmarshall_uint32( &(hdr->sequence_id), &offset, buf );
unmarshall_uint32( &(hdr->crc), &offset, buf );
print_header( "Unmarshalled ", hdr );
return offset;
}
/* ************************************** */
SOCKET open_socket(int local_port, int udp_sock, int server_mode) {
SOCKET sock_fd;
struct sockaddr_in local_address;
int sockopt = 1;
if((sock_fd = socket(PF_INET, udp_sock ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) {
traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n",
strerror(errno), sock_fd);
return(-1);
}
#ifndef WIN32
/* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */
#endif
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
memset(&local_address, 0, sizeof(local_address));
local_address.sin_family = AF_INET;
local_address.sin_port = htons(local_port);
local_address.sin_addr.s_addr = INADDR_ANY;
if(bind(sock_fd, (struct sockaddr*) &local_address, sizeof(local_address)) == -1) {
traceEvent(TRACE_ERROR, "Bind error [%s]\n", strerror(errno));
return(-1);
}
if((!udp_sock) && server_mode) {
if(listen(sock_fd, 255) == -1) {
traceEvent(TRACE_ERROR, "Listen error [%s]\n", strerror(errno));
return(-1);
}
}
return(sock_fd);
}
/* ************************************** */
int connect_socket(int sock_fd, struct peer_addr* _dest) {
char *http_header;
int len, rc;
struct sockaddr_in dest;
peer_addr2sockaddr_in(_dest, &dest);
/* FIX: add IPv6 support */
rc = connect(sock_fd, (struct sockaddr*)&dest, sizeof(struct sockaddr_in));
if(rc == -1) {
traceEvent(TRACE_WARNING, "connect() error [%s]\n", strerror(errno));
return(-1);
}
/* Send dummy http header */
http_header = "GET / HTTP/1.0\r\n\r\n";
len = strlen(http_header);
rc = send(sock_fd, http_header, len, 0);
return((rc == len) ? 0 : -1);
}
/* *********************************************** */
void send_packet(n2n_sock_info_t * sinfo,
char *packet, size_t *packet_len,
const struct peer_addr *remote_peer, u_int8_t compress_data) {
int data_sent_len;
data_sent_len = unreliable_sendto(sinfo,
packet, packet_len, remote_peer, compress_data);
if(data_sent_len != *packet_len)
traceEvent(TRACE_WARNING,
"sendto() [sent=%d][attempted_to_send=%d] [%s]\n",
data_sent_len, *packet_len, strerror(errno));
}
/* *********************************************** */
int traceLevel = 2 /* NORMAL */;
int useSyslog = 0, syslog_opened = 0;
#define N2N_TRACE_DATESIZE 32
void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) {
va_list va_ap;
if(eventTraceLevel <= traceLevel) {
char buf[2048];
char out_buf[640];
char theDate[N2N_TRACE_DATESIZE];
char *extra_msg = "";
time_t theTime = time(NULL);
#ifdef WIN32
int i;
#endif
/* We have two paths - one if we're logging, one if we aren't
* Note that the no-log case is those systems which don't support it (WIN32),
* those without the headers !defined(USE_SYSLOG)
* those where it's parametrically off...
*/
memset(buf, 0, sizeof(buf));
strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime));
va_start (va_ap, format);
vsnprintf(buf, sizeof(buf)-1, format, va_ap);
va_end(va_ap);
if(eventTraceLevel == 0 /* TRACE_ERROR */)
extra_msg = "ERROR: ";
else if(eventTraceLevel == 1 /* TRACE_WARNING */)
extra_msg = "WARNING: ";
while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
#ifndef WIN32
if(useSyslog) {
if(!syslog_opened) {
openlog("n2n", LOG_PID, LOG_DAEMON);
syslog_opened = 1;
}
snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf);
syslog(LOG_INFO, out_buf);
} else {
snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf);
printf("%s\n", out_buf);
fflush(stdout);
}
#else
/* this is the WIN32 code */
for(i=strlen(file)-1; i>0; i--) if(file[i] == '\\') { i++; break; };
snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, &file[i], line, extra_msg, buf);
printf("%s\n", out_buf);
fflush(stdout);
#endif
}
}
/* *********************************************** */
/* addr should be in network order. Things are so much simpler that way. */
char* intoa(u_int32_t /* host order */ addr, char* buf, u_short buf_len) {
char *cp, *retStr;
u_int byte;
int n;
cp = &buf[buf_len];
*--cp = '\0';
n = 4;
do {
byte = addr & 0xff;
*--cp = byte % 10 + '0';
byte /= 10;
if (byte > 0) {
*--cp = byte % 10 + '0';
byte /= 10;
if (byte > 0)
*--cp = byte + '0';
}
*--cp = '.';
addr >>= 8;
} while (--n > 0);
/* Convert the string to lowercase */
retStr = (char*)(cp+1);
return(retStr);
}
/* *********************************************** */
char* macaddr_str(const char *mac, char *buf, int buf_len) {
snprintf(buf, buf_len, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF);
return(buf);
}
/* *********************************************** */
void fill_standard_header_fields(n2n_sock_info_t * sinfo,
struct n2n_packet_header *hdr, char *src_mac) {
socklen_t len = sizeof(hdr->private_ip);
memset(hdr, 0, N2N_PKT_HDR_SIZE);
hdr->version = N2N_PKT_VERSION;
hdr->crc = 0; // FIX
if(src_mac != NULL) memcpy(hdr->src_mac, src_mac, 6);
getsockname(sinfo->sock, (struct sockaddr*)&hdr->private_ip, &len);
hdr->public_ip.family = AF_INET;
}
/* *********************************************** */
void send_ack(n2n_sock_info_t * sinfo,
u_int16_t last_rcvd_seq_id,
struct n2n_packet_header *header,
struct peer_addr *remote_peer,
char *src_mac) {
/* marshalling double-checked. */
struct n2n_packet_header hdr;
u_int8_t pkt[ N2N_PKT_HDR_SIZE ];
size_t len = sizeof(hdr);
size_t len2;
int compress_data = N2N_COMPRESSION_ENABLED;
fill_standard_header_fields(sinfo, &hdr, src_mac);
hdr.msg_type = MSG_TYPE_ACK_RESPONSE;
hdr.sequence_id = last_rcvd_seq_id;
memcpy(hdr.community_name, header->community_name, COMMUNITY_LEN);
len2=marshall_n2n_packet_header( pkt, &hdr );
assert( len2 == len );
send_packet(sinfo, (char*)pkt, &len, remote_peer, compress_data);
}
/* *********************************************** */
u_int8_t is_multi_broadcast(char *dest_mac) {
return(((!memcmp(broadcast_addr, dest_mac, 6))
|| (!memcmp(multicast_addr, dest_mac, 3))) ? 1 : 0);
}
/* *********************************************** */
/* http://www.faqs.org/rfcs/rfc908.html */
u_int receive_data(n2n_sock_info_t * sinfo,
char *packet, size_t packet_len,
struct peer_addr *from, u_int8_t *discarded_pkt,
char *tun_mac_addr, u_int8_t decompress_data,
struct n2n_packet_header *hdr) {
socklen_t fromlen = sizeof(struct sockaddr_in);
int len;
char *payload, *pkt_type;
macstr_t src_mac_buf;
macstr_t dst_mac_buf;
ipstr_t ip_buf;
ipstr_t from_ip_buf;
if(sinfo->is_udp_socket) {
struct sockaddr_in _from;
len = recvfrom(sinfo->sock, packet, packet_len, 0, (struct sockaddr*)&_from, &fromlen);
sockaddr_in2peer_addr(&_from, from);
} else {
len = recv(sinfo->sock, packet, 4, 0);
if(len == 4) {
packet[4] = '\0';
len = atoi(packet);
len = recv(sinfo->sock, packet, len, 0);
} else {
traceEvent(TRACE_WARNING, "Unable to receive n2n packet length");
return(-1);
}
}
unmarshall_n2n_packet_header(hdr, (u_int8_t *)packet);
payload = &packet[N2N_PKT_HDR_SIZE];
if(len < 0) {
#ifdef WIN32
if(WSAGetLastError() != WSAECONNRESET /* http://support.microsoft.com/kb/263823 */ ) {
traceEvent(TRACE_WARNING, "recvfrom returned %d [err=%d]", len, WSAGetLastError());
}
#endif
return(0);
} else if(len > MIN_COMPRESSED_PKT_LEN) {
#define N2N_DECOMPRESS_BUFSIZE 2048
char decompressed[N2N_DECOMPRESS_BUFSIZE];
int rc;
lzo_uint decompressed_len=N2N_DECOMPRESS_BUFSIZE;
size_t insize = len-N2N_PKT_HDR_SIZE;
if(decompress_data) {
rc = lzo1x_decompress_safe((u_char*)&packet[N2N_PKT_HDR_SIZE],
insize,
(u_char*)decompressed, &decompressed_len, NULL);
if(rc == LZO_E_OK)
{
traceEvent(TRACE_INFO, "%u bytes decompressed into %u", insize, decompressed_len);
}
else
{
traceEvent(TRACE_WARNING, "Failed to decompress %u byte packet. LZO error=%d", insize, rc );
return -1;
}
if(packet_len > decompressed_len) {
memcpy(&packet[N2N_PKT_HDR_SIZE], decompressed, decompressed_len);
len = decompressed_len+N2N_PKT_HDR_SIZE;
} else {
traceEvent(TRACE_WARNING, "Uncompressed packet is too large [decompressed_len=%d]",
decompressed_len);
return(0);
}
}
(*discarded_pkt) = 0;
if(!hdr->sent_by_supernode) {
memcpy( &packet[offsetof(struct n2n_packet_header, public_ip)], from, sizeof(struct sockaddr_in) );
}
switch(hdr->pkt_type) {
case packet_unreliable_data:
pkt_type = "unreliable data";
break;
case packet_reliable_data:
pkt_type = "reliable data";
break;
case packet_ping:
pkt_type = "ping";
break;
case packet_pong:
pkt_type = "pong";
break;
default:
pkt_type = "???";
}
traceEvent(TRACE_INFO, "+++ Received %s packet [rcvd_from=%s:%d][msg_type=%s][seq_id=%d]",
pkt_type,
intoa(ntohl(from->addr_type.v4_addr), from_ip_buf, sizeof(from_ip_buf)),
ntohs(from->port), msg_type2str(hdr->msg_type),
hdr->sequence_id);
traceEvent(TRACE_INFO, " [src_mac=%s][dst_mac=%s][original_sender=%s:%d]",
macaddr_str(hdr->src_mac, src_mac_buf, sizeof(src_mac_buf)),
macaddr_str(hdr->dst_mac, dst_mac_buf, sizeof(dst_mac_buf)),
intoa(ntohl(hdr->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)),
ntohs(hdr->public_ip.port));
#ifdef HANDLE_RETRANSMISSION
if((hdr->pkt_type == packet_reliable_data)
&& (hdr->msg_type == MSG_TYPE_PACKET)) {
(*discarded_pkt) = handle_ack(sock_fd, is_udp_socket, hdr,
&payload[6], payload, from, tun_mac_addr);
} else
(*discarded_pkt) = 0;
#endif
} else
traceEvent(TRACE_WARNING, "Receive error [%s] or pkt too short [len=%d]\n",
strerror(errno), len);
return(len);
}
/* *********************************************** */
#if 0
static u_int32_t queue_packet(struct send_hash_entry *scan,
char *packet,
u_int16_t packet_len) {
struct packet_list *pkt = (struct packet_list*)malloc(sizeof(struct packet_list));
if(pkt == NULL) {
traceEvent(TRACE_ERROR, "Not enough memory!");
return(0);
}
if((pkt->packet = (char*)malloc(packet_len)) == NULL) {
traceEvent(TRACE_ERROR, "Not enough memory!");
return(0);
}
memcpy(pkt->packet, packet, packet_len);
pkt->packet_len = packet_len;
pkt->seq_id = scan->last_seq_id;
pkt->next = scan->unacked_packet_list;
scan->unacked_packet_list = pkt;
scan->num_unacked_pkts++;
return(pkt->seq_id);
}
#endif
/* *********************************************** */
/* Work-memory needed for compression. Allocate memory in units
* of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
*/
#define HEAP_ALLOC(var,size) \
lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS);
/* ******************************************************* */
u_int send_data(n2n_sock_info_t * sinfo,
char *packet, size_t *packet_len,
const struct peer_addr *to, u_int8_t compress_data) {
char compressed[1650];
int rc;
lzo_uint compressed_len=0;
struct sockaddr_in destsock;
if(*packet_len < N2N_PKT_HDR_SIZE) {
traceEvent(TRACE_WARNING, "The packet about to be sent is too short [len=%d]\n", *packet_len);
return(-1);
}
memcpy(compressed, packet, N2N_PKT_HDR_SIZE);
peer_addr2sockaddr_in(to, &destsock);
if(compress_data) {
rc = lzo1x_1_compress((u_char*)&packet[N2N_PKT_HDR_SIZE],
*packet_len - N2N_PKT_HDR_SIZE,
(u_char*)&compressed[N2N_PKT_HDR_SIZE],
&compressed_len, wrkmem);
if ( 0 == compressed_len )
{
traceEvent(TRACE_WARNING, "failed to compress %u bytes.", (*packet_len - N2N_PKT_HDR_SIZE) );
return -1;
}
compressed_len += N2N_PKT_HDR_SIZE;
traceEvent(TRACE_INFO, "%u bytes compressed into %u", *packet_len, compressed_len);
/* *packet_len = compressed_len; */
if(sinfo->is_udp_socket) {
rc = sendto(sinfo->sock, compressed, compressed_len, 0,
(struct sockaddr*)&destsock, sizeof(struct sockaddr_in));
} else {
char send_len[5];
/* 4 bytes packet length */
snprintf(send_len, sizeof(send_len), "%04d", (int)compressed_len);
if((rc = send(sinfo->sock, send_len, 4, 0)) != 4)
return(-1);
if((rc = send(sinfo->sock, compressed, compressed_len, 0)) != compressed_len) {
traceEvent(TRACE_WARNING, "send error [%d][%s]",
errno, strerror(errno));
}
}
} else {
compressed_len = *packet_len;
if(sinfo->is_udp_socket)
rc = sendto(sinfo->sock, packet, compressed_len, 0,
(struct sockaddr*)&destsock, sizeof(struct sockaddr_in));
else {
char send_len[5];
/* 4 bytes packet length */
snprintf(send_len, sizeof(send_len), "%04d", (int)compressed_len);
if((rc = send(sinfo->sock, send_len, 4, 0)) != 4)
return(-1);
rc = send(sinfo->sock, compressed, compressed_len, 0);
}
if(rc == -1) {
ipstr_t ip_buf;
traceEvent(TRACE_WARNING, "sendto() failed while attempting to send data to %s:%d",
intoa(ntohl(to->addr_type.v4_addr), ip_buf, sizeof(ip_buf)),
ntohs(to->port));
}
}
if ( rc >= 0) {
traceEvent(TRACE_INFO, "### Tx N2N Msg -> network");
}
if(rc == compressed_len)
return(*packet_len); /* fake just to avoid warnings */
else
return(rc);
}
/* *********************************************** */
u_int reliable_sendto(n2n_sock_info_t * sinfo,
char *packet, size_t *packet_len,
const struct peer_addr *to, u_int8_t compress_data) {
/* char *payload = &packet[N2N_PKT_HDR_SIZE]; */
struct n2n_packet_header hdr_storage;
struct n2n_packet_header *hdr = &hdr_storage;
macstr_t src_mac_buf;
macstr_t dst_mac_buf;
/* REVISIT: efficiency of unmarshal + re-marshal just to change a couple of bits. */
unmarshall_n2n_packet_header( hdr, (u_int8_t *)packet );
/* hdr->sequence_id = (hdr->msg_type == MSG_TYPE_PACKET) ? mac2sequence((u_char*)payload, packet, *packet_len) : 0; */
hdr->sequence_id = 0;
hdr->pkt_type = packet_reliable_data;
traceEvent(TRACE_INFO, "Sent reliable packet [msg_type=%s][seq_id=%d][src_mac=%s][dst_mac=%s]",
msg_type2str(hdr->msg_type), hdr->sequence_id,
macaddr_str(&packet[6], src_mac_buf, sizeof(src_mac_buf)),
macaddr_str(packet, dst_mac_buf, sizeof(dst_mac_buf)));
marshall_n2n_packet_header( (u_int8_t *)packet, hdr );
return(send_data(sinfo, packet, packet_len, to, compress_data));
}
/* *********************************************** */
/* unreliable_sendto is passed a fully marshalled, packet. Its purpose is to set
* the unreliable flags but leave the rest of the packet untouched. */
u_int unreliable_sendto(n2n_sock_info_t * sinfo,
char *packet, size_t *packet_len,
const struct peer_addr *to, u_int8_t compress_data) {
struct n2n_packet_header hdr_storage;
struct n2n_packet_header *hdr = &hdr_storage;
macstr_t src_mac_buf;
macstr_t dst_mac_buf;
/* REVISIT: efficiency of unmarshal + re-marshal just to change a couple of bits. */
unmarshall_n2n_packet_header( hdr, (u_int8_t *)packet );
hdr->sequence_id = 0; /* Unreliable messages have 0 as sequence number */
hdr->pkt_type = packet_unreliable_data;
traceEvent(TRACE_INFO, "Sent unreliable packet [msg_type=%s][seq_id=%d][src_mac=%s][dst_mac=%s]",
msg_type2str(hdr->msg_type), hdr->sequence_id,
macaddr_str(hdr->src_mac, src_mac_buf, sizeof(src_mac_buf)),
macaddr_str(hdr->dst_mac, dst_mac_buf, sizeof(dst_mac_buf)));
marshall_n2n_packet_header( (u_int8_t *)packet, hdr );
return(send_data(sinfo, packet, packet_len, to, compress_data));
}
/* *********************************************** */
char* msg_type2str(u_short msg_type) {
switch(msg_type) {
case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER");
case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER");
case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET");
case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK");
case MSG_TYPE_ACK_RESPONSE: return("MSG_TYPE_ACK_RESPONSE");
}
return("???");
}
/* *********************************************** */
void hexdump(char *buf, u_int len) {
u_int i;
for(i=0; i<len; i++) {
if((i > 0) && ((i % 16) == 0)) printf("\n");
printf("%02X ", buf[i] & 0xFF);
}
printf("\n");
}
/* *********************************************** */
void print_n2n_version() {
printf("Welcome to n2n v.%s for %s\n"
"Built on %s\n"
"Copyright 2007-08 - http://www.ntop.org\n\n",
version, osName, buildDate);
}
/** Find the peer entry in list with mac_addr equal to mac.
*
* Does not modify the list.
*
* @return NULL if not found; otherwise pointer to peer entry.
*/
struct peer_info * find_peer_by_mac( struct peer_info * list, const char * mac )
{
while(list != NULL)
{
if( 0 == memcmp(mac, list->mac_addr, 6) )
{
return list;
}
list = list->next;
}
return NULL;
}
/** Return the number of elements in the list.
*
*/
size_t peer_list_size( const struct peer_info * list )
{
size_t retval=0;
while ( list )
{
++retval;
list = list->next;
}
return retval;
}
/** Add new to the head of list. If list is NULL; create it.
*
* The item new is added to the head of the list. New is modified during
* insertion. list takes ownership of new.
*/
void peer_list_add( struct peer_info * * list,
struct peer_info * new )
{
new->next = *list;
new->last_seen = time(NULL);
*list = new;
}
size_t purge_expired_registrations( struct peer_info ** peer_list ) {
static time_t last_purge = 0;
time_t now = time(NULL);
size_t num_reg = 0;
if((now - last_purge) < PURGE_REGISTRATION_FREQUENCY) return 0;
traceEvent(TRACE_INFO, "Purging old registrations");
num_reg = purge_peer_list( peer_list, now-REGISTRATION_TIMEOUT );
last_purge = now;
traceEvent(TRACE_INFO, "Remove %ld registrations", num_reg);
return num_reg;
}
/** Purge old items from the peer_list and return the number of items that were removed. */
size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before )
{
struct peer_info *scan;
struct peer_info *prev;
size_t retval=0;
scan = *peer_list;
prev = NULL;
while(scan != NULL)
{
if(scan->last_seen < purge_before)
{
struct peer_info *next = scan->next;
if(prev == NULL)
{
*peer_list = next;
}
else
{
prev->next = next;
}
++retval;
free(scan);
scan = next;
}
else
{
prev = scan;
scan = scan->next;
}
}
return retval;
}
static u_int8_t hex2byte( const char * s )
{
char tmp[3];
tmp[0]=s[0];
tmp[1]=s[1];
tmp[2]=0; /* NULL term */
return((u_int8_t)strtol( s, NULL, 16 ));
}
extern int str2mac( u_int8_t * outmac /* 6 bytes */, const char * s )
{
size_t i;
/* break it down as one case for the first "HH", the 5 x through loop for
* each ":HH" where HH is a two hex nibbles in ASCII. */
*outmac=hex2byte(s);
++outmac;
s+=2; /* don't skip colon yet - helps generalise loop. */
for (i=1; i<6; ++i )
{
s+=1;
*outmac=hex2byte(s);
++outmac;
s+=2;
}
return 0; /* ok */
}