/* * (C) 2007-09 - Luca Deri * Richard Andrews * * 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 * * Code contributions courtesy of: * Richard Andrews * Massimo Torquati * */ #include "n2n.h" #include "minilzo.h" #include #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 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 */ }