From: David Parrish Date: Thu, 2 Sep 2004 04:20:21 +0000 (+0000) Subject: sync X-Git-Tag: 2.2.1-2fdn3.1~19^2^2~1^2~419 X-Git-Url: http://git.sameswireless.fr/l2tpns.git/commitdiff_plain/3b2aece7c57ea8e7bac74373fc2bfee3852199a7 sync --- diff --git a/test/bounce.c b/test/bounce.c new file mode 100644 index 0000000..5443b67 --- /dev/null +++ b/test/bounce.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 39000 + +void sigalarm(int junk); +unsigned long long recv_count = 0; +unsigned long pps = 0; +unsigned long bytes = 0; +unsigned long dropped = 0, seq = 0; +unsigned port = PORT; + +int main(int argc, char *argv[]) +{ + int on = 1; + struct sockaddr_in addr; + int s; + char *packet; + + while ((s = getopt(argc, argv, "?p:")) > 0) + { + switch (s) + { + case 'p' : + port = atoi(optarg); + break; + case '?' : + printf("Options:\n"); + printf("\t-p port to listen on\n"); + return(0); + break; + } + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(s, (void *) &addr, sizeof(addr)) < 0) + { + perror("bind"); + return -1; + } + + signal(SIGALRM, sigalarm); + alarm(1); + + printf("Waiting on port %d\n", port); + packet = (char *)malloc(65535); + while (1) + { + struct sockaddr_in addr; + int alen = sizeof(addr), l; + unsigned int iseq; + + l = recvfrom(s, packet, 65535, 0, (void *) &addr, &alen); + if (l < 0) continue; + recv_count++; + pps++; + bytes += l; + iseq = *((unsigned int *) packet); + if (seq != iseq) + dropped += (iseq - seq); + seq = iseq + 1; + + sendto(s, packet, l, 0, (struct sockaddr *)&addr, alen); + } + + free(packet); +} + +void sigalarm(int junk) +{ + printf("Recv: %10llu %0.1fMbits/s (%lu pps) (%5ld dropped)\n", recv_count, (bytes / 1024.0 / 1024.0 * 8), pps, dropped); + pps = bytes = 0; + alarm(1); +} + diff --git a/test/generateload.c b/test/generateload.c new file mode 100644 index 0000000..c3a40b6 --- /dev/null +++ b/test/generateload.c @@ -0,0 +1,1290 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPPLCP 0xc021 +#define PPPPAP 0xc023 +#define PPPCHAP 0xc223 +#define PPPIPCP 0x8021 +#define PPPIP 0x0021 +#define PPPCCP 0x80fd + +#define CONFREQ 1 +#define CONFACK 2 +#define CONFNAK 3 +#define CONFREJ 4 +#define TERMREQ 5 +#define TERMACK 6 +#define CODEREJ 7 +#define PROTREJ 8 +#define ECHOREQ 9 +#define ECHOREP 10 +#define DISCREQ 11 + +#define PACKET_LENGTH 1000 +#define TARGET_PPS 5000 +#define TARGET "211.29.131.33" +#define GWADDR "211.29.131.30" +#define NUM_SESSIONS 1 +#define MAX_PACKETS 0 +#define AVG_SIZE 5 + +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned char u8; + +char *lcp_codes[] = { + "reserved", + "CONFREQ", + "CONFACK", + "CONFNAK", + "CONFREJ", + "TERMREQ", + "TERMACK", + "CODEREJ", + "PROTREJ", + "ECHOREQ", + "ECHOREP", + "DISCREQ", +}; + +char *mtypes[] = { + "reserved", + "SCCRQ", + "SCCRP", + "SCCCN", + "StopCCN", // 4 + "reserved", + "HELLO", + "OCRQ", + "OCRP", + "OCCN", + "ICRQ", // 10 + "ICRP", + "ICCN", + "reserved", + "CDN", + "WEN", // 15 + "SLI", +}; + +char *attributes[] = { + "Message Type", // 0 + "Result Code", // 1 + "Protocol Version", // 2 + "Framing Capabilities", // 3 + "Bearer Capabilities", // 4 + "Tie Breaker", // 5 + "Firmware Revision", // 6 + "Host Name", // 7 + "Vendor Name", // 8 + "Assigned Tunnel ID", // 9 + "Receive Window Size", // 10 + "Challenge", // 11 + "Q.931 Cause Code", // 12 + "Challenge Response", // 13 + "Assigned Session ID", // 14 + "Call Serial Number", // 15 + "Minimum BPS", // 16 + "Maximum BPS", // 17 + "Bearer Type", // 18 (2 = Analog, 1 = Digital) + "Framing Type", // 19 (2 = Async, 1 = Sync) + "Reserved 20", // 20 + "Called Number", // 21 + "Calling Number", // 22 + "Sub Address", // 23 + "Tx Connect Speed", // 24 + "Physical Channel ID", // 25 + "Initial Received LCP CONFREQ", // 26 + "Last Sent LCP CONFREQ", // 27 + "Last Received LCP CONFREQ", // 28 + "Proxy Authen Type", // 29 + "Proxy Authen Name", // 30 + "Proxy Authen Challenge", // 31 + "Proxy Authen ID", // 32 + "Proxy Authen Response", // 33 + "Call Errors", // 34 + "ACCM", // 35 + "Random Vector", // 36 + "Private Group ID", // 37 + "Rx Connect Speed", // 38 + "Sequencing Required", // 39 +}; + +char *result_codes[] = { + "Reserved", + "General request to clear control connection", + "General error--Error Code indicates the problem", + "Control channel already exists", + "Requester is not authorized to establish a control channel", + "The protocol version of the requester is not supported", + "Requester is being shut down", + "Finite State Machine error", +}; + +char *error_codes[] = { + "No general error", + "No control connection exists yet for this LAC-LNS pair", + "Length is wrong", + "One of the field values was out of range or reserved field was non-zero", + "Insufficient resources to handle this operation now", + "The Session ID is invalid in this context", + "A generic vendor-specific error occurred in the LAC", + "Try another LNS", + "Session or tunnel was shutdown due to receipt of an unknown AVP with the M-bit set", +}; + + +typedef struct +{ + char buf[4096]; + int length; +} controlt; + +typedef struct avp_s +{ + int length; + int type; + struct avp_s *next; + char value[1024]; +} avp; + +typedef struct +{ + int length; + u16 session; + u16 tunnel; + u16 ns; + u16 nr; + u16 mtype; + char *buf; + avp *first; + avp *last; +} control_message; + +typedef struct { +unsigned long long send_count , recv_count ; +unsigned long long spkt , rpkt ; +unsigned int dropped; +unsigned long sbytes , rbytes ; +int quitit; +struct sessiont +{ + short remote_session; + char open; + int ppp_state; + unsigned char ppp_identifier; + int addr; +} sessions[65536]; + +int active_sessions ; +} sharedt; + +sharedt * ss; + +void controlsend(controlt * c, short t, short s); +void controlnull(short t); +controlt *controlnew(u16 mtype); +void controls(controlt * c, u16 avp, char *val, u8 m); +void control16(controlt * c, u16 avp, u16 val, u8 m); +void control32(controlt * c, u16 avp, u32 val, u8 m); +void controlfree(controlt *c); +control_message *parsecontrol(char *buf, int length); +void dump_control_message(control_message *c); +u32 avp_get_32(control_message *c, int id); +u16 avp_get_16(control_message *c, int id); +char *avp_get_s(control_message *c, int id); +void reader_thread(int udpfd); +void skip_zlb(); +void cm_free(control_message *m); +controlt *ppp_new(u16 session, int protocol); +void ppp_free(controlt *packet); +controlt *ppp_lcp(u16 s, unsigned char type, char identifier); +controlt *ppp_ipcp(u16 s, unsigned char type, char identifier); +void ppp_send(controlt *c); +void ppp_add_16(controlt * c, u16 val); +void ppp_add_32(controlt * c, u32 val); +void ppp_add_s(controlt * c, char *val); +void ppp_lcp_add_option(controlt *c, unsigned char option, unsigned char length, int data); +void dump_ppp_packet(char *packet, int l); +controlt *ppp_pap(u16 s, unsigned char type, char identifier, char *username, char *password); +char *inet_toa(unsigned long addr); +__u16 checksum(unsigned char *addr, int count); +void sigalarm(int junk); +void sigint(int signal); +void clean_shutdown(); +void print_report(); + +pthread_t pthread_reader; + +int ns = 0, nr = 0; +int udpfd; +int t = 0; +struct sockaddr_in gatewayaddr = {0}; +int numsessions = NUM_SESSIONS; +int packet_length = PACKET_LENGTH; +int target_pps = TARGET_PPS; +char *target = TARGET; +char *gwaddr = GWADDR; +int max_packets = MAX_PACKETS; +int ppsend; +int do_init = 1; +char **session_usernames; +char *base_username = "dslloadtest"; +char *base_password = "testing"; +char *suffix = "@optusnet.com.au"; + +int main(int argc, char *argv[]) +{ + int s; + char *packet; + + ss = (sharedt*) mmap(NULL, sizeof(*ss), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); + + // Process Arguments {{{ + while ((s = getopt(argc, argv, "?hs:g:l:p:m:t:nU:P:")) > 0) + { + switch (s) + { + case 's' : + numsessions = atoi(optarg); + if (numsessions <= 0) + { + printf("You must have at least 1 session\n"); + return -1; + } + break; + case 'l' : + packet_length = atoi(optarg); + if (packet_length < 64) + { + printf("You must have at least 64 byte packets\n"); + return -1; + } + break; + case 'n' : + do_init = 0; + break; + case 'p' : + target_pps = atoi(optarg); + break; + case 'm' : + max_packets = atoi(optarg); + if (packet_length < 64) + { + printf("You must send at least 50 packets.\n"); + return -1; + } + break; + case 't' : + target = strdup(optarg); + break; + case 'g' : + gwaddr = strdup(optarg); + break; + case 'U' : + base_username = strdup(optarg); + break; + case 'P' : + base_password = strdup(optarg); + break; + case 'h' : + case '?' : + printf("Options:\n"); + printf("\t-s number of ss->sessions\n"); + printf("\t-l packet length\n"); + printf("\t-p target pps\n"); + printf("\t-m maximum number of packets\n"); + printf("\t-t target IP address\n"); + printf("\t-g gateway IP address\n"); + printf("\t-U username (or base if multiple)\n"); + printf("\t-P password\n"); + return(0); + break; + } + } + if (target_pps) + ppsend = target_pps / 50; + else + ppsend = 0; + + packet = calloc(4096, 1); + + memset(ss->sessions, 0, sizeof(ss->sessions)); + + if (do_init) + printf("Creating %d ss->sessions to %s\n", numsessions, gwaddr); + printf("Targeting %d packets per second\n", target_pps); + if (max_packets) printf("Sending a maximum of %d packets\n", max_packets); + printf("Sending packets to %s\n", target); + printf("Sending %d byte packets\n", packet_length); + + session_usernames = (char **)calloc(sizeof(char *), numsessions); + if (numsessions > 1) + { + int sul = strlen(base_username) + 10; + int i; + + for (i = 0; i < numsessions; i++) + { + session_usernames[i] = (char *)calloc(sul, 1); + snprintf(session_usernames[i], sul, "%s%d", base_username, i+1); + } + } + else + { + session_usernames[0] = strdup(base_username); + } + // }}} + + // Create socket/*{{{*/ + { + int on = 1; + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(38001); + + udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (udpfd <= 0) + { + perror("socket"); + return -1; + } + + setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(udpfd, (void *) &addr, sizeof(addr)) < 0) + { + perror("bind"); + return -1; + } + + printf("Bound to port %d\n", htons(addr.sin_port)); + }/*}}}*/ + + gatewayaddr.sin_family = AF_INET; + gatewayaddr.sin_port = htons(1701); + inet_aton(gwaddr, &gatewayaddr.sin_addr); + + // Create tunnel/*{{{*/ + if (do_init) { + controlt *c; + control_message *r; + + c = controlnew(1); // SCCRQ + controls(c, 7, "loadtest", 0); // Tunnel Hostname + controls(c, 8, "OIE", 0); // Vendor Name + control16(c, 9, 1, 0); // Assigned Tunnel ID + control16(c, 2, 256, 0); // Version 1.0 + control16(c, 3, 1, 0); // Framing (Async) + control16(c, 4, 1, 0); // Bearer (Digital) + control16(c, 10, 20, 0); // Receive Window Size + controlsend(c, 0, 0); + controlfree(c); + + // Receive reply/*{{{*/ + { + struct sockaddr_in addr; + int alen = sizeof(addr), l; + + l = recvfrom(udpfd, packet, 4096, 0, (void *) &addr, &alen); + if (l < 0) + { + printf("Error creating tunnel: %s\n", strerror(errno)); + return -1; + } + printf("Received "); + r = parsecontrol(packet, l); + if (!r->first) + { + printf("Invalid packet.. no first avp\n"); + return -1; + } + + printf("Assigned tunnel: %d\n", t = avp_get_16(r, 9)); + cm_free(r); + + c = controlnew(3); // SCCCN + controlsend(c, t, 0); + controlfree(c); + skip_zlb(); + }/*}}}*/ + }/*}}}*/ + + + // Create ss->sessions/*{{{*/ + if (do_init) + { + for (s = 1; s <= numsessions; s++) + { + controlt *c; + + c = controlnew(10); // ICRQ + controls(c, 21, "12356", 0); // Called Number + controls(c, 22, "000", 0); // Calling Number + control16(c, 14, s, 0); // Assigned Session ID + controlsend(c, t, 0); + controlfree(c); + usleep(15000); // 15 ms + } + } + printf("All session create requests sent...\n");/*}}}*/ + + if ( fork() == 0) { + reader_thread(udpfd); + exit(0); + } + + { + char tmp[512]; + fprintf(stderr, "Press enter to begin sending traffic\n"); + fgets(tmp, 512, stdin); + } + + fprintf(stderr, "Beginning sending traffic through %d ss->sessions\n", ss->active_sessions); + printf(" TS: Total Packets Sent\n"); + printf(" TL: Total Packets Lost\n"); + printf(" PL: Packet Loss\n"); + printf(" SS: Send Speed\n"); + printf(" RS: Receive Speed\n"); + printf(" SP: Packets/Second Sent\n"); + printf(" RP: Packets/Second Received\n"); + printf(" NS: Number of active ss->sessions\n"); + + signal(SIGALRM, sigalarm); + signal(SIGINT, sigint); + alarm(1); + + // Traffic generation loop {{{ + { + struct sockaddr_in to; + struct iphdr *iph; + struct udphdr *udph; + char *data; + int len = 0; + unsigned int seq = 0; + controlt *c; + + // Get address + memset(&to, 0, sizeof(struct sockaddr_in)); + to.sin_family = AF_INET; + inet_aton(target, &to.sin_addr); + + c = ppp_new(1, PPPIP); + + iph = (struct iphdr *)(c->buf + c->length); + udph = (struct udphdr *)(c->buf + c->length + sizeof(struct iphdr)); + data = (char *)(c->buf + c->length + sizeof(struct iphdr) + sizeof(struct udphdr)); + len = sizeof(struct iphdr) + sizeof(struct udphdr); + c->length += len; + + //IP + c->length += sizeof(struct iphdr); + iph->tos = 0; + iph->id = ntohs(1); + iph->frag_off = ntohs(1 << 14); + iph->ttl = 30; + iph->check = 0; + iph->version = 4; + iph->ihl = 5; + iph->protocol = 17; + memcpy(&iph->daddr, &to.sin_addr, sizeof(iph->daddr)); + + // UDP + udph->source = ntohs(39999); + udph->dest = ntohs(39000); + udph->check = 0; + + // Data + memset(data, 64, 1500); + + udph->len = ntohs(sizeof(struct udphdr) + packet_length); + iph->tot_len = ntohs(len + packet_length); + c->length += packet_length; + + while (!ss->quitit && ss->active_sessions) + { + int i; + for (i = 1; i <= numsessions && !ss->quitit; i++) + { + // Skip ss->sessions that aren't active yet + if (!ss->sessions[i].open || ss->sessions[i].ppp_state != 2) + continue; + + *(u16 *)(c->buf + 4) = htons(ss->sessions[i].remote_session); // Session ID + iph->saddr = ss->sessions[i].addr; + iph->check = 0; + iph->check = ntohs(checksum((char *)iph, sizeof(struct iphdr))); + + *((unsigned int *) data) = seq++; + ppp_send(c); + + ss->send_count++; + ss->spkt++; + ss->sbytes += c->length; + + if (ppsend && ss->send_count % ppsend == 0) + { + struct timespec req; + req.tv_sec = 0; + req.tv_nsec = 5 * 1000 * 1000; + nanosleep(&req, NULL); + } + + if (max_packets && ss->send_count >= max_packets) ss->quitit++; + } + } + + c->length -= packet_length; + + }/*}}}*/ + + clean_shutdown(); + print_report(); + + close(udpfd); + return 0; +} + +void print_report() +{ + float loss; + + loss = 100 - (((ss->recv_count * 1.0) / (ss->send_count * 1.0)) * 100.0); + + printf("\n"); + printf("Total Packets Sent: %llu\n", ss->send_count); + printf("Total Packets Received: %llu\n", ss->recv_count); + printf("Overall Packet Loss: %0.2f%%", loss); + printf("\n"); +} + +void clean_shutdown()/*{{{*/ +{ + int i; + for (i = 0; i < numsessions; i++) + { + // Close Session + controlt *c; + + if (!ss->sessions[i].open) continue; + c = controlnew(14); // CDN + control16(c, 14, i, 0); // Assigned Session ID + control16(c, 1, 1, 0); // Result Code + controlsend(c, t, ss->sessions[i].remote_session); + controlfree(c); + } + + // Close Tunnel + { + controlt *c; + + c = controlnew(4); // StopCCN + control16(c, 9, 1, 0); // Assigned Tunnel ID + control16(c, 1, 1, 0); // Result Code + controlsend(c, t, 0); + controlfree(c); + } +}/*}}}*/ + +void sigint(int signal) +{ + ss->quitit++; +} + +void sigalarm(int junk) +{ + static unsigned long long last_rpkts[AVG_SIZE], last_spkts[AVG_SIZE]; + static int last = 0, avg_count = 0; + register unsigned int avg_s = 0, avg_r = 0, i; + float loss; + + last_rpkts[last] = ss->rpkt; + last_spkts[last] = ss->spkt; + last = (last + 1) % AVG_SIZE; + if (avg_count < AVG_SIZE) avg_count++; + + for (i = 0; i < avg_count; i++) + { + avg_s += last_spkts[i]; + avg_r += last_rpkts[i]; + } + avg_s /= avg_count; + avg_r /= avg_count; + + loss = 100 - (((avg_r * 1.0) / (avg_s * 1.0)) * 100.0); + fprintf(stderr, "TS:%llu TL:%lld DR:%4d PL:%-3.2f%% SS:%0.1fMbits/s RS:%0.1fMbits/s NS:%u SP:%u RP:%u\n", + ss->send_count, ss->send_count-ss->recv_count, ss->dropped, loss, + (ss->sbytes/1024.0/1024.0*8), (ss->rbytes/1024.0/1024.0*8), + ss->active_sessions, + avg_s, avg_r); + + ss->spkt = ss->rpkt = 0; + ss->sbytes = ss->rbytes = 0; + alarm(1); +} + +__u16 checksum(unsigned char *addr, int count) +{ + register long sum = 0; + + for (; count > 1; count -= 2) + { + sum += ntohs(*(u32 *)addr); + addr += 2; + } + + if (count > 1) sum += *(unsigned char *)addr; + + // take only 16 bits out of the 32 bit sum and add up the carries + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + // one's complement the result + sum = ~sum; + + return ((u16) sum); +} + +// Control Stuff {{{ +void control16(controlt * c, u16 avp, u16 val, u8 m) +{ + u16 l = (m ? 0x8008 : 0x0008); + *(u16 *) (c->buf + c->length + 0) = htons(l); + *(u16 *) (c->buf + c->length + 2) = htons(0); + *(u16 *) (c->buf + c->length + 4) = htons(avp); + *(u16 *) (c->buf + c->length + 6) = htons(val); + c->length += 8; +} + +// add an AVP (32 bit) +void control32(controlt * c, u16 avp, u32 val, u8 m) +{ + u16 l = (m ? 0x800A : 0x000A); + *(u16 *) (c->buf + c->length + 0) = htons(l); + *(u16 *) (c->buf + c->length + 2) = htons(0); + *(u16 *) (c->buf + c->length + 4) = htons(avp); + *(u32 *) (c->buf + c->length + 6) = htonl(val); + c->length += 10; +} + +// add an AVP (32 bit) +void controls(controlt * c, u16 avp, char *val, u8 m) +{ + u16 l = ((m ? 0x8000 : 0) + strlen(val) + 6); + *(u16 *) (c->buf + c->length + 0) = htons(l); + *(u16 *) (c->buf + c->length + 2) = htons(0); + *(u16 *) (c->buf + c->length + 4) = htons(avp); + memcpy(c->buf + c->length + 6, val, strlen(val)); + c->length += 6 + strlen(val); +} + +// new control connection +controlt *controlnew(u16 mtype) +{ + controlt *c; + c = calloc(sizeof(controlt), 1); + c->length = 12; + control16(c, 0, mtype, 1); + return c; +} + +void controlnull(short t) +{ + controlt *c; + c = calloc(sizeof(controlt), 1); + c->length = 12; + controlsend(c, t, 0); + controlfree(c); + ns--; +} + +// add a control message to a tunnel, and send if within window +void controlsend(controlt * c, short t, short s) +{ + *(u16 *) (c->buf + 0) = htons(0xC802); // flags/ver + *(u16 *) (c->buf + 2) = htons(c->length); // length + *(u16 *) (c->buf + 4) = htons(t); // tunnel + *(u16 *) (c->buf + 6) = htons(s); // session + *(u16 *) (c->buf + 8) = htons(ns++); // sequence + *(u16 *) (c->buf + 10) = htons(nr); // sequence +// printf("Sending "); +// cm_free(parsecontrol(c->buf, c->length)); + sendto(udpfd, c->buf, c->length, 0, (struct sockaddr *)&gatewayaddr, sizeof(gatewayaddr)); +} + +void controlfree(controlt *c) +{ + if (!c) return; + free(c); +} + +control_message *parsecontrol(char *buf, int length) +{ + char *p = buf; + control_message *c; + + c = calloc(sizeof(control_message), 1); + c->buf = buf; + c->length = length; + + c->tunnel = ntohs(*(u16 *)(buf + 4)); + c->session = ntohs(*(u16 *)(buf + 6)); + c->ns = ntohs(*(u16 *)(buf + 8)); + c->nr = nr = ntohs(*(u16 *)(buf + 10)); + p += 12; + while ((p - buf) < length) + { + avp *a = calloc(sizeof(avp), 1); + a->length = ntohs(*(short *)(p)) & 0x3FF; + a->type = ntohs(*(short *)(p + 4)); + memcpy(a->value, p + 6, a->length - 6); + if (a->type == 0) c->mtype = ntohs(*(short *)a->value); + p += a->length; + if (c->last) + c->last->next = a; + else + c->first = a; + c->last = a; + } + if (c->first) + dump_control_message(c); + return c; +} + +void dump_control_message(control_message *c) +{ + avp *a; + printf("Control Message (type=%u s=%u t=%d ns=%d nr=%d)\n", c->mtype, c->session, c->tunnel, c->ns, c->nr); + for (a = c->first; a; a = a->next) + { + printf(" avp: %s, len: %d", attributes[a->type], a->length - 6); + switch (a->type) + { + // Short + case 6 : + case 9 : + case 10 : + case 39 : + case 14 : printf(", value: %u\n", ntohs(*(short *)a->value)); + break; + + // Integer + case 16 : + case 17 : + case 24 : + case 25 : + case 38 : + case 15 : printf(", value: %u\n", ntohl(*(u32 *)a->value)); + break; + + // String + case 7 : + case 21 : + case 22 : + case 23 : + case 37 : + case 8 : printf(", value: \"%s\"\n", a->value); + break; + + case 2 : printf(", value: %d.%d\n", *(char *)a->value, *(char *)a->value + 1); + break; + case 0 : printf(", value: %s\n", mtypes[ntohs(*(short *)a->value)]); + break; + case 19 : + case 3 : printf(", value: (%d) %s %s\n", ntohl(*(u32 *)a->value), + (ntohl(*(u32 *)a->value) & 0x01) ? "synchronous" : "", + (ntohl(*(u32 *)a->value) & 0x02) ? "asynchronous" : ""); + break; + case 18 : + case 4 : printf(", value: (%d) %s %s\n", ntohl(*(u32 *)a->value), + (ntohl(*(u32 *)a->value) & 0x01) ? "digital" : "", + (ntohl(*(u32 *)a->value) & 0x02) ? "analog" : ""); + break; + + default : printf("\n"); + break; + } + } + printf("\n"); +} + +u16 avp_get_16(control_message *c, int id) +{ + avp *a; + + for (a = c->first; a; a = a->next) + if (a->type == id) return ntohs(*(short *)a->value); + return 0; +} + +u32 avp_get_32(control_message *c, int id) +{ + avp *a; + + for (a = c->first; a; a = a->next) + if (a->type == id) return ntohl(*(u32 *)a->value); + return 0; +} + +char *avp_get_s(control_message *c, int id) +{ + avp *a; + + for (a = c->first; a; a = a->next) + if (a->type == id) return (char *)a->value; + return 0; +} + +void cm_free(control_message *m) +{ + avp *a, *n; + + for (a = m->first; a; ) + { + n = a->next; + free(a); + a = n; + } + + free(m); +} + +// }}} + +void reader_thread(int updfd)/*{{{*/ +{ + unsigned char *packet; + unsigned int seq = 0; + + printf("Starting reader thread\n"); + packet = malloc(4096); + while (!ss->quitit) + { + struct sockaddr_in addr; + int alen = sizeof(addr); + control_message *m; + int l; + int s; + int pfc = 0; + +// memset(packet, 0, 4096); + if ((l = recvfrom(udpfd, packet, 4096, 0, (void *) &addr, &alen)) < 0) break; + ss->rbytes += l; + if (!do_init) + { + ss->recv_count++; + ss->rpkt++; + continue; + } + if (l < 12) + { + printf("Short packet received: %d bytes\n", l); + } + s = ntohs(*(u16 *)(packet + 4)); + if (!s) + { + printf("Invalid session ID\n"); + continue; + } + if (packet[0] == 0xc8) + { + // Control Packet + printf("Reader Received "); + m = parsecontrol(packet, l); + printf("\n"); + s = m->session; + + switch (m->mtype) + { + case 4 : printf("StopCCN\n"); + printf("Killing tunnel %d\n", avp_get_16(m, 9)); + ss->quitit++; + break; + case 6 : printf("HELLO, sending ZLB ACK\n"); + controlnull(t); + break; + case 11 : + { + controlt *c; + + printf("Received ICRP. Responding with CONFREQ\n"); + + ss->sessions[s].remote_session = avp_get_16(m, 14); + ss->sessions[s].open = 1; + ss->sessions[s].ppp_state = 1; + + c = controlnew(12); // ICCN + controlsend(c, t, ss->sessions[s].remote_session); + controlfree(c); + + c = ppp_lcp(s, CONFREQ, 0); + ppp_lcp_add_option(c, 1, 2, htons(1500)); // MRU = 1400 + ppp_lcp_add_option(c, 3, 2, htons(0xC023)); // Authentication Protocol - PAP + ppp_send(c); + controlfree(c); + break; + } + case 14 : { + int s; + printf("CDN\n"); + s = avp_get_16(m, 14); + printf("Killing session %d\n", s); + ss->sessions[s].open = 0; + ss->sessions[s].ppp_state = 0; + ss->active_sessions--; + controlnull(t); + break; + } + + } + if (m->mtype == 4) + { + printf("StopCCN Received.. Dieing\n"); + ss->quitit++; + break; + } + cm_free(m); + } + else + { + // Data Packet + unsigned short protocol = ntohs(*(u16 *)(packet + 6)); + + if (protocol == 0xff03) + { + pfc = 2; + packet += 2; + protocol = ntohs(*(u16 *)(packet + 6)); + } + if (protocol != PPPIP) + { + printf("Received "); + dump_ppp_packet(packet + 6, l - 6); + } + + if (protocol == PPPLCP) + { + controlt *r; + unsigned char ppp_id = *(char *)(packet + 9); + + switch (*(char *)(packet + 8)) + { + case CONFREQ : + r = ppp_lcp(s, CONFACK, ppp_id); + ppp_send(r); + break; + case CONFACK : + r = ppp_pap(s, CONFREQ, 0, session_usernames[s-1], base_password); + ppp_send(r); + break; + case TERMREQ : + r = ppp_lcp(s, TERMACK, ppp_id); + ppp_send(r); + break; + case ECHOREQ : + r = ppp_lcp(s, ECHOREP, ppp_id); + ppp_add_32(r, 0); + ppp_send(r); + break; + } + } + else if (protocol == PPPIPCP) + { + controlt *r; + int taddr = 0; + u32 address = *(u32 *)(packet + 14); + + switch (*(char *)(packet + 8)) + { + case CONFREQ : + r = ppp_ipcp(s, CONFREQ, time(NULL) % 255); + ppp_lcp_add_option(r, 3, 4, htonl(taddr)); // Request 0.0.0.0 + ppp_send(r); + controlfree(r); + r = ppp_ipcp(s, CONFACK, time(NULL) % 255); + ppp_lcp_add_option(r, 3, 4, address); // ACK gateway IP + ppp_send(r); + controlfree(r); + break; + case CONFNAK : + // Ack whatever address we are given - it's ours + r = ppp_ipcp(s, CONFACK, time(NULL) % 255); + ppp_lcp_add_option(r, 3, 4, address); // Request 0.0.0.0 + ppp_send(r); + controlfree(r); + printf("Session %d: %s\n", s, inet_toa(address)); + ss->sessions[s].ppp_state = 2; + ss->sessions[s].addr = address; + ss->active_sessions++; + break; + case CONFACK : + printf("Conf-Ack Received\n"); + break; + case TERMREQ : + printf("Term-Req Received\n"); + break; + case ECHOREQ : + printf("Echo-Req Received\n"); + break; + case ECHOREP : + printf("Echo-Rep Received\n"); + break; + } + } + else if (protocol == PPPPAP) + { + if (*(u16 *)(packet + 8) == 3) + { + controlt *c; + printf("Closing Connection\n"); + + c = controlnew(14); // CDN + control16(c, 14, ss->sessions[s].remote_session, 0); // Assigned Session ID + controlsend(c, t, 0); + controlfree(c); + ss->sessions[s].open = 0; + } + } + else if (protocol == PPPIP) + { + struct iphdr *iph = (struct iphdr *)(packet + 8); + char * data = (char*) (packet + 8 + sizeof(struct iphdr) + sizeof(struct udphdr)); + if (!ss->sessions[s].open) + { + printf("Packet for closed session %d\n", s); + continue; + } + + if (iph->protocol == 17) + { + int iseq; + ss->recv_count++; + ss->rpkt++; + iseq = *((unsigned int *) data); + if (seq != iseq) { + ss->dropped += (iseq - seq) ; + } + seq = iseq + 1; // Next sequence number to expect. + } + } + } + packet -= pfc; + } + free(packet); + + printf("Closing reader thread\n"); + +}/*}}}*/ + +void skip_zlb() /*{{{*/ +{ + struct sockaddr_in addr; + int alen = sizeof(addr); + char buf[1024]; + int l; + l = recvfrom(udpfd, buf, 1024, MSG_PEEK, (void *) &addr, &alen); + if (l < 0) + { + printf("recvfrom: %s\n", strerror(errno)); + return; + } + if (l <= 12) + { + printf("Skipping ZLB (l=%d)\n", l); + recvfrom(udpfd, buf, 1024, 0, (void *) &addr, &alen); + } +} +/*}}}*/ + +// PPP Stuff {{{ +controlt *ppp_new(u16 session, int protocol) +{ + controlt *c = calloc(sizeof(controlt), 1); + *(u16 *)(c->buf + 4) = htons(ss->sessions[session].remote_session); // Tunnel + *(u16 *)(c->buf + 6) = htons(protocol); + c->length += 8; + + return c; +} + +void ppp_free(controlt *c) +{ + free(c); +} + +controlt *ppp_lcp(u16 s, unsigned char type, char identifier) +{ + controlt *c; + + if (!identifier) identifier = ss->sessions[s].ppp_identifier++; + c = ppp_new(s, PPPLCP); + *(char *)(c->buf + c->length + 0) = type; + *(char *)(c->buf + c->length + 1) = identifier; + *(u16 *)(c->buf + c->length + 2) = ntohs(4); + c->length += 4; + + return c; +} + +controlt *ppp_ipcp(u16 s, unsigned char type, char identifier) +{ + controlt *c; + + if (!identifier) identifier = ss->sessions[s].ppp_identifier++; + c = ppp_new(s, PPPIPCP); + *(char *)(c->buf + c->length + 0) = type; + *(char *)(c->buf + c->length + 1) = identifier; + *(u16 *)(c->buf + c->length + 2) = ntohs(4); + c->length += 4; + + return c; +} + +controlt *ppp_pap(u16 s, unsigned char type, char identifier, char *username, char *password) +{ + controlt *c; + + if (!identifier) identifier = ss->sessions[s].ppp_identifier++; + c = ppp_new(s, PPPPAP); + *(char *)(c->buf + c->length + 0) = type; + *(char *)(c->buf + c->length + 1) = identifier; + *(u16 *)(c->buf + c->length + 2) = ntohs(4); + c->length += 4; + + *(char *)(c->buf + c->length) = strlen(username) + strlen(suffix); + memcpy((c->buf + c->length + 1), username, strlen(username)); + memcpy((c->buf + c->length + 1 + strlen(username)), suffix, strlen(suffix)); + c->length += strlen(username) + 1 + strlen(suffix); + + *(char *)(c->buf + c->length) = strlen(password); + memcpy((c->buf + c->length + 1), password, strlen(password)); + c->length += strlen(password) + 1; + + return c; +} + +void ppp_send(controlt *c) +{ + *(u16 *)(c->buf + 0) = htons(0x0002); // flags/ver + *(u16 *)(c->buf + 2) = htons(t); // tunnel + *(u16 *)(c->buf + 10) = ntohs(c->length - 8); + if (sendto(udpfd, c->buf, c->length, 0, (struct sockaddr *)&gatewayaddr, sizeof(gatewayaddr)) < 0) + perror("sendto"); + if (htons(*(u16 *)(c->buf + 6)) != PPPIP) + { + printf("PPP Sending "); + dump_ppp_packet(c->buf + 6, c->length - 6); + } +} + +void ppp_add_16(controlt *c, u16 val) +{ + *(u16 *) (c->buf + c->length) = htons(val); + c->length += 2; +} + +void ppp_add_32(controlt *c, u32 val) +{ + *(u32 *) (c->buf + c->length) = htons(val); + c->length += 4; +} + +void ppp_add_s(controlt *c, char *val) +{ + memcpy(c->buf + c->length, val, strlen(val)); + c->length += strlen(val); +} + +void ppp_lcp_add_option(controlt *c, unsigned char option, unsigned char length, int data) +{ + *(char *)(c->buf + c->length + 0) = option; + *(char *)(c->buf + c->length + 1) = length + 2; + memcpy(c->buf + c->length + 2, &data, length); + c->length += 2 + length; +} + +void dump_ppp_packet(char *packet, int l) +{ + char *p = packet; + int protocol ; + if (*(unsigned char *)p == 0xff) p += 2; + protocol = ntohs(*(u16 *)(p)); + printf("PPP Packet\n"); + switch (protocol) + { + case PPPCCP : printf(" Protocol: PPPCCP\n"); break; + } + if (protocol == PPPLCP) + { + printf(" Protocol: PPPLCP\n"); + printf(" LCP Code: %s\n", lcp_codes[*(u8 *)(p + 2)]); + } + else if (protocol == PPPPAP) + { + printf(" Protocol: PPPPAP\n"); + if (*(char *)(p + 2) == 2) + { + printf(" Authentication accepted\n"); + } + else if (*(char *)(p + 2) == 3) + { + printf(" Authentication denied\n"); + } + } + else if (protocol == PPPIPCP) + { + printf(" Protocol: PPPIPCP\n"); + printf(" IPCP Code: %s\n", lcp_codes[*(u8 *)(p + 2)]); + printf(" Address: %s\n", inet_toa(*(u32 *)(p + 8))); + } + else if (protocol == PPPIP) + { + struct iphdr *iph; + struct protoent *pr; + + iph = (struct iphdr *)(p + 2); + + printf(" Protocol: PPPIP\n"); + printf(" Length: %d\n", l); + printf(" IP Version: %d\n", iph->version); + if (iph->version != 4) return; + pr = getprotobynumber(iph->protocol); + printf(" IP Header Length: %d\n", iph->ihl); + printf(" IP TTL: %d\n", iph->ttl); + printf(" IP Protocol: %s (%d)\n", (pr ? pr->p_name : "unknown"), iph->protocol); + printf(" IP Checksum: %x\n", ntohs(iph->check)); + } + else + { + printf(" Protocol: unknown 0x%x\n", protocol); + } + printf("\n"); +} + +char *inet_toa(unsigned long addr) +{ + struct in_addr in; + memcpy(&in, &addr, sizeof(unsigned long)); + return inet_ntoa(in); +} + +// }}} +