tsctp.c
// tsctp.c TPS SCTP handler #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/sctp.h> #include <uuid/uuid.h> #include <openssl/md5.h> #include "tsctp.h" #define MAX_MESSAGE_SIZE 2048 #define SUCCESS 0 #define FAILURE -1 // the following are expected to come from the client user settings #define SERVER_IP "192.168.6.25" #define SERVER_PORT "8000" #define FIRSTNAME "Test1" #define LASTNAME "Avatar" #define PASSWORD "qwe456" float Version = 0.1; int Sfd; // file descriptor for socket // This is a small wrapper for stand-alone testing int main(int argc, char *argv[]){ unsigned char recv_buffer[MAX_MESSAGE_SIZE]; struct sctp_sndrcvinfo sndrcvinfo; int length; int flags; int stream; char notif[9]; // attempt connect to server if (tscpt_connect(SERVER_IP, SERVER_PORT) == FAILURE){ exit(EXIT_FAILURE); } while(1){ // check for a reply length = sctp_recvmsg(Sfd, (void *)recv_buffer, MAX_MESSAGE_SIZE, (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags ); stream = sndrcvinfo.sinfo_stream; if(flags & MSG_NOTIFICATION){ memcpy(notif, recv_buffer, 8); notif[8] = '\0'; printf("Notification: %s\n", notif); }else{ if(length > 0){ printf("Received %d bytes on stream %d\n", length, stream); tscpt_decode(recv_buffer, length); } } } exit(EXIT_SUCCESS); } int tscpt_connect(const char* ip, const char* port){ struct addrinfo hints; struct addrinfo *result, *rp; struct sctp_event_subscribe events; // struct sctp_status status; // int in, ret; int error; /* Obtain address(es) matching host/port */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = IPPROTO_SCTP; error = getaddrinfo(ip, port, &hints, &result); if (error != 0) { printf("Error: getaddrinfo: %s\n", gai_strerror(error)); return(FAILURE); } /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect(2). If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp != NULL; rp = rp->ai_next) { Sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (Sfd == -1) continue; // failed if (connect(Sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; // Success! close(Sfd); // try the next one } if (rp == NULL) { // No address succeeded fprintf(stderr, "Could not connect\n"); return(FAILURE); } // else rp conatins the address that we have connected to freeaddrinfo(result); // No longer needed /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */ memset( (void *)&events, 0, sizeof(events) ); events.sctp_data_io_event = 1; error = setsockopt( Sfd, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events) ); /* Read and emit the status of the Socket (optional step) * / in = sizeof(status); ret = getsockopt( Sfd, SOL_SCTP, SCTP_STATUS, (void *)&status, (socklen_t *)&in ); printf("assoc id = %d\n", status.sstat_assoc_id ); printf("state = %d\n", status.sstat_state ); printf("instrms = %d\n", status.sstat_instrms ); printf("outstrms = %d\n", status.sstat_outstrms ); */ return(SUCCESS); } void tscpt_decode(unsigned char* recv_buffer, int length){ unsigned char* ptr; float ver; int type; int i; int l; char text[50]; printf("Received:\n"); print_buffer(recv_buffer, length); type = 0; ptr = recv_buffer; memcpy(&type, ptr, 2); ptr += 2; switch(type){ case 0x0001: // version is sent on connect // also maybe Public Key, in future memcpy(&ver, ptr, 4); if(ver != Version){ printf("Version mismatch, Client=%f Server=%f\n", Version, ver); }else{ printf("Version ok = %f\n", ver); try_login(); } break; case 0x0003: // login result i = 0; memcpy(&i, ptr, 1); ptr ++; length = 0; memcpy(&l, ptr, 2); ptr +=2; memcpy(text, ptr, l); ptr += l; printf("%s Code=%d\n", text, i); break; default: printf("Unknown messag type %x\n", type); break; } } void try_login(){ // const char password[17]; unsigned char passwdhash[32]; unsigned char message[50]; unsigned char* ptr; int location; int length; int i; location = 0; // start at home // hash the pw md5(PASSWORD, passwdhash); printf("PW Hash %s\n",passwdhash); // Future: encode with Public Key // assemble message ptr = message; i = 0x0002; // type login message memcpy(ptr, &i, 2); ptr += 2; strncpy((char *)ptr, "$1$", 3); // pw prefix ptr += 3; memcpy(ptr, passwdhash, 32); // password ptr += 32; length = strlen(FIRSTNAME) + strlen(LASTNAME) + 1; memcpy(ptr, &length, 1); // length of names ptr += 1; length = strlen(FIRSTNAME); strncpy((char *)ptr, FIRSTNAME, length); //first ptr += length; strncpy((char *)ptr, ".", 1); //. ptr += 1; length = strlen(LASTNAME); // last strncpy((char *)ptr, LASTNAME, length); ptr += length; memcpy(ptr, &location, 1); // where ptr += 1; length = ptr - message; print_buffer(message, length); tscpt_send(message, length); } /*Encode str to str_enc using md5 algorithm*/ void md5(char *str, unsigned char *str_enc) { int i = 0; unsigned char d[16]; MD5_CTX ctx; MD5_Init(&ctx); MD5_Update (&ctx, (char *) str, strlen(str)); MD5_Final(d, &ctx); for (i = 0; i < 16; i++) { sprintf((char *)str_enc + (i*2), "%02X", d[i]); } str_enc[32] = 0; } int tscpt_send( unsigned char* message, int length){ int ret; ret = sctp_sendmsg(Sfd, message, (size_t)length, NULL, 0, 0, 0, 0, 0, 0 ); if(ret == length){ return(SUCCESS); } printf("Error: tscpt_send sent %d of %d characters.\n", ret, length); return(FAILURE ); } void print_buffer(unsigned char *buffer, int mlen){ int n = 0; int p = 0; while(n<mlen){ printf("%02x ", buffer[n]); p = 0; n++; if(n%8 == 0) printf(" "); if(n%16 == 0){ printf("\n"); p = 1; } } if(p == 0) printf("\n"); printf("\n"); }
tsctp.h
//tsctp.h // TPS SCTP header file int tscpt_connect(const char* ip, const char* port); int tscpt_receive(unsigned char* recv_buffer); void tscpt_decode(unsigned char* recv_buffer, int length); void try_login(); void md5(char *str, unsigned char *str_enc); int tscpt_send( unsigned char* message, int length); void print_buffer(unsigned char *buffer, int mlen);
Makefile
# Makefile for TPS SCTP handler CC = gcc CFLAGS = -Wall -g all: tsctp tsctp: tsctp.o $(CC) $(CFLAGS) -o $@ tsctp.c -L/usr/local/lib -lsctp -lssl -luuid clean: rm -f tsctp *.o