Author: marten Date: Mon Oct 19 20:59:44 2009 New Revision: 1236 Log: Added Community-Operator protocol and renamed functions in co_server.c to underscore names Added: trunk/community-operator/co_common_packets.h Modified: trunk/community-operator/Makefile.am trunk/community-operator/co_client.c trunk/community-operator/co_server.c Modified: trunk/community-operator/Makefile.am ============================================================================== --- trunk/community-operator/Makefile.am Mon Oct 19 17:37:26 2009 (r1235) +++ trunk/community-operator/Makefile.am Mon Oct 19 20:59:44 2009 (r1236) @@ -19,6 +19,7 @@ INCLUDES += -I@PISA_HIPL_SRCDIR@/libinet6 INCLUDES += -I@PISA_HIPL_SRCDIR@/libhiptool INCLUDES += -I@PISA_HIPL_SRCDIR@/libdht +INCLUDES += -I@PISA_HIPL_SRCDIR@/opendht INCLUDES += -I@PISA_HIPL_SRCDIR@/hipd INCLUDES += -I@PISA_HIPL_SRCDIR@/i3/i3_client INCLUDES += -I@PISA_HIPL_SRCDIR@/pjproject/pjnath/include Modified: trunk/community-operator/co_client.c ============================================================================== --- trunk/community-operator/co_client.c Mon Oct 19 17:37:26 2009 (r1235) +++ trunk/community-operator/co_client.c Mon Oct 19 20:59:44 2009 (r1236) @@ -6,7 +6,9 @@ #include <errno.h> #include <stdio.h> +#include "co_common_packets.h" #include "config.h" +#include "debug.h" #include <sys/socket.h> #include <arpa/inet.h> @@ -15,6 +17,10 @@ #include <string.h> #include <unistd.h> +static void print_deny_reason(int reason); + +static int sock; + /** * Write a certificate to a file. * @@ -38,6 +44,26 @@ } /** + * Prints the corresponding deny reason to the given reason number. + * @param reason Reason number + */ +static void print_deny_reason(int reason) +{ + PISA_ERROR("Certificate request denied:\n"); + switch (reason) { + case DENY_HIT_EXPIRED: + PISA_ERROR("The HIT has expired.\n"); + break; + case DENY_HIT_NOT_ALLOWED: + PISA_ERROR("The HIT is not allowed to request certificates.\n"); + break; + case DENY_UNKNOWN_ERROR: + PISA_ERROR("An unknown error occurred.\n"); + break; + } +} + +/** * Create a UDP socket connected to the server with a receive timeout. * * @param srv_addr HIT of the server @@ -78,10 +104,27 @@ */ static int sendRequest(void) { - if (send(sock, "blah", 4, 0) != 4) { - printf("failed to request the certificate\n"); + int sent; + co_packet *packet; + packet = malloc(sizeof(co_packet)); + + packet->message_type = MESSAGE_CERTIFICATE_REQUEST; + + sent = send(sock, packet, sizeof(co_packet), 0); + free(packet); + if (sent == -1) { + PISA_ERROR("send failed.\n"); + return -1; } + + if (sent != sizeof(co_packet)) { + PISA_ERROR("sent bytes (%i) do not match expected value (%i).\n", sent, + sizeof(co_packet)); + + return -1; + } + return 0; } @@ -94,27 +137,44 @@ */ static int receiveCertificate(char **cert) { - char buffer[10240] = ""; + co_packet *packet; ssize_t count; + int result; *cert = NULL; - if ((count = recv(sock, buffer, sizeof(buffer) -1, 0)) == -1) { - printf("Receive failed (errno %i): %s\n", errno, - strerror(errno)); + packet = malloc(sizeof(co_packet)); + + if ((count = recv(sock, packet, sizeof(co_packet), 0)) == -1) { + PISA_ERROR("Receive failed (errno %i): %s\n", errno, strerror(errno)); if (errno == EAGAIN) - return -2; - return -1; + result = -2; + result = -1; } - buffer[count] = 0; - if (!strcmp(buffer, "denied")) { - printf("Community operator server denied the certificate.\n"); - return -1; + switch (packet->message_type) { + case MESSAGE_CERTIFICATE_DENY: + print_deny_reason(packet->message.deny.reason); + result = -1; + break; + case MESSAGE_CERTIFICATE_ACCEPT: + PISA_INFO("Certificate request approved!\n"); + *cert = strdup(packet->message.cert.cert); + result = 0; + break; + case MESSAGE_ERROR: + PISA_ERROR("Error(%i): %s\n", packet->message.error.error_type, + packet->message.error.error_message); + result = -1; + break; + default: + PISA_ERROR("Unknown error occurred.\n"); + result = -2; + break; } - *cert = strdup(buffer); - return 0; + free(packet); + return result; } int main(int argc, char **argv) Added: trunk/community-operator/co_common_packets.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/community-operator/co_common_packets.h Mon Oct 19 20:59:44 2009 (r1236) @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, Distributed Systems Group, RWTH Aachen + * All rights reserved. + */ + +#ifndef PISA_CO_COMMON_PACKETS_H +#define PISA_CO_COMMON_PACKETS_H + +#include "global.h" + +#define LENGTH_ERROR_MESSAGE 128 + +// Message types +#define MESSAGE_CERTIFICATE_REQUEST 0 +#define MESSAGE_CERTIFICATE_DENY 1 +#define MESSAGE_CERTIFICATE_ACCEPT 2 +#define MESSAGE_ERROR 3 + +// Deny reasons +#define DENY_HIT_NOT_ALLOWED 0 +#define DENY_HIT_EXPIRED 1 +#define DENY_UNKNOWN_ERROR 2 + +typedef struct co_certificate_request +{ + +} __attribute__ ((packed)) co_certificate_request; + +typedef struct co_certificate_deny +{ + uint8_t reason; +} __attribute__ ((packed)) co_certificate_deny; + +typedef struct co_certificate +{ + char cert[PISA_CERT_LENGTH]; +} __attribute__ ((packed)) co_certificate; + +typedef struct co_error +{ + uint8_t error_type; + uint8_t error_message[LENGTH_ERROR_MESSAGE]; +} __attribute__ ((packed)) co_error; + +/* General Community-Operator packet */ +typedef struct co_packet +{ + uint8_t message_type; + + union message { + co_certificate_request request; + co_certificate_deny deny; + co_certificate cert; + co_error error; + } message; + +} __attribute__ ((packed)) co_packet; + +#endif /* PISA_CO_COMMON_PACKETS_H */ Modified: trunk/community-operator/co_server.c ============================================================================== --- trunk/community-operator/co_server.c Mon Oct 19 17:37:26 2009 (r1235) +++ trunk/community-operator/co_server.c Mon Oct 19 20:59:44 2009 (r1236) @@ -7,37 +7,52 @@ #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> +#include <sys/select.h> +#include <signal.h> #include "ac_config.h" #include "global.h" #include "debug.h" +#include "co_common_packets.h" #include "config.h" #include "hitlist.h" #include "hipl.h" -#define BUFSIZE 10240 #define CERT_BUF_SIZE 10240 +#define DEFAULT_NUMBER_OF_PARALLEL_USERS 3 +static int running; static struct in6_addr issuer_hit; static pisa_hitlist *allowed = NULL; +static int sock; + +static int create_server_socket(void); +static int answer_certificate_query(struct sockaddr_in6 *cl_addr); +static void co_quit(int quitcode); +static char *get_certificate_for_hit(struct in6_addr *hit, int *reason); +static int handle_packet(struct sockaddr_in6 *socket_addr, + co_packet *co_packet); +#ifdef HIPL_CERTIFICATE_CHANGES +static int get_number_of_parallel_users(pisa_hitlist_entry *entry); +#endif /* HIPL_CERTIFICATE_CHANGES */ /** * Create a socket and port specified in the config file. * * @return filedescriptor for the socket */ -static int createServerSocket(void) +static int create_server_socket(void) { int s, one = 1, port; struct sockaddr_in6 addr = { 0 }; if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == 0) { - printf("socket() failed.\n"); + PISA_ERROR("socket() failed.\n"); exit(-1); } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1 ) - printf("setsockopt failed with SO_REUSEADDR.\n"); + PISA_ERROR("setsockopt failed with SO_REUSEADDR.\n"); pisa_cfg_get_int_value("port", &port); @@ -46,16 +61,37 @@ addr.sin6_port = htons(port); if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - printf("bind failed.\n"); + PISA_ERROR("bind failed.\n"); exit(-1); } - printf("socket created and bound to port %i\n", port); + PISA_INFO("socket created and bound to port %i\n", port); return s; } /** + * Terminate community-operator server by receiving signal + * @param signal signal quit code + */ +static void co_quit(int quitcode) +{ + switch (quitcode) { + case SIGTERM: + case SIGINT: + case SIGQUIT: + case SIGBUS: + PISA_INFO("Shutting down Community-Operator Server...\n"); + running = 0; + break; + + case SIGILL: + case SIGPIPE: + break; + } +} + +/** * Request a certificate for a specified hit, if all requirements are met: * - HIT must be whitelisted in the allowed HIT list. * - expiration date for that HIT must not be in the past. @@ -64,13 +100,17 @@ * date is within that week. * * @param hit HIT of the requesting host + * @param reason Pointer to an int which holds the reason for the deny * @return pointer to certificate on success, NULL otherwise */ -static char *getCertificateForHit(struct in6_addr *hit) +static char *get_certificate_for_hit(struct in6_addr *hit, int *reason) { char *cert; time_t not_before, not_after; pisa_hitlist_entry *conn; +#ifdef HIPL_CERTIFICATE_CHANGES + int parallel_users; +#endif /* HIPL_CERTIFICATE_CHANGES */ time(¬_before); time(¬_after); @@ -78,110 +118,223 @@ /* certificate for one week */ not_after += 7 * 24 * 60 * 60; - if (!(conn = pisa_hitlist_find(allowed, hit))) + if (!(conn = pisa_hitlist_find(allowed, hit))) { + *reason = DENY_HIT_NOT_ALLOWED; return NULL; - if (conn->expiration < not_before) + } + if (conn->expiration < not_before) { + *reason = DENY_HIT_EXPIRED; return NULL; - if (conn->expiration < not_after) + } + if (conn->expiration < not_after) { not_after = conn->expiration; + } + +#ifdef HIPL_CERTIFICATE_CHANGES + parallel_users = get_number_of_parallel_users(conn); +#endif /* HIPL_CERTIFICATE_CHANGES */ + cert = malloc(CERT_BUF_SIZE); +#ifndef HIPL_CERTIFICATE_CHANGES if (createCertificate(¬_before, ¬_after, hit, &issuer_hit, cert, CERT_BUF_SIZE) != 0) { +#else + if (createCertificate(¬_before, ¬_after, hit, &issuer_hit, + parallel_users, cert, CERT_BUF_SIZE) != 0) { +#endif /* HIPL_CERTIFICATE_CHANGES */ + free(cert); + *reason = DENY_UNKNOWN_ERROR; return NULL; } return cert; } -static int sock; +#ifdef HIPL_CERTIFICATE_CHANGES +/** + * Reads the number of allowed parallel users from the configuration file + * for the given HIT + * @param entry The pisa_hitlist_entry for which the number should be read out + * @return Either the number which is entered in the configuration file + * or DEFAULT_NUMBER_OF_PARALLEL_USERS + */ +static int get_number_of_parallel_users(pisa_hitlist_entry *entry) +{ + config_setting_t *users; + users = config_setting_get_member(entry->group, "parallel_users"); + if (users != NULL) { + return config_setting_get_int(users); + } else { + return DEFAULT_NUMBER_OF_PARALLEL_USERS; + } +} +#endif /* HIPL_CERTIFICATE_CHANGES */ /** * Process a request from a specified client and send back the result - * @todo specify protocol * * @param cl_addr client that requested the certificate + * @return 1 -> success; 0 -> error; */ -static void answerCertificateQuery(struct sockaddr_in6 *cl_addr) +static int answer_certificate_query(struct sockaddr_in6 *cl_addr) { char *cert; - int bytes, sent; - - if (!(cert = getCertificateForHit(&cl_addr->sin6_addr))) { - cert = strdup("denied"); + int sent; + int reason = 0; + co_packet *packet; + + packet = malloc(sizeof(co_packet)); + + if (!(cert = get_certificate_for_hit(&cl_addr->sin6_addr, &reason))) { + // Deny request + packet->message_type = MESSAGE_CERTIFICATE_DENY; + packet->message.deny.reason = reason; + } else { + // Accept request + packet->message_type = MESSAGE_CERTIFICATE_ACCEPT; + strncpy(packet->message.cert.cert, cert, strlen(cert)); } - bytes = strlen(cert); - if ((sent = sendto(sock, cert, bytes, 0, (struct sockaddr *) cl_addr, - sizeof(struct sockaddr_in6))) == -1) { - printf("sendto failed.\n"); + sent = sendto(sock, packet, sizeof(co_packet), 0, + (struct sockaddr *) cl_addr, sizeof(struct sockaddr_in6)); + if (sent == -1) { + PISA_ERROR("sendto failed.\n"); free(cert); - return; + return 0; } - if (bytes != sent) - printf("sent bytes (%i) do not match expected value (%i).\n", - sent, bytes); - else - printf("the request has been answered.\n"); + if (sent != sizeof(co_packet)) { + PISA_ERROR("sent bytes (%i) do not match expected value (%i).\n", sent, + sizeof(co_packet)); + return 0; + } else { + PISA_INFO("the request has been answered.\n"); + return 1; + } free(cert); + free(packet); } int main(int argc, char **argv) { + + signal(SIGTERM, co_quit); + signal(SIGINT, co_quit); + signal(SIGQUIT, co_quit); + signal(SIGILL, co_quit); + signal(SIGPIPE, SIG_IGN); + signal(SIGBUS, co_quit); + int received; size_t addrlen; + char *addr_string; + co_packet *packet; struct sockaddr_in6 cl_addr = { 0 }; - char *buf, *addr_string; if (getuid() != 0) { - printf("You're not root. HIPD won't sign certificates.\n"); + PISA_ERROR("You're not root. HIPD won't sign certificates.\n"); return -1; } - buf = malloc(BUFSIZE); + running = 1; + + packet = malloc(sizeof(co_packet)); addr_string = malloc(INET6_ADDRSTRLEN); + pisa_cfg_authorized_hosts_setup_file("co_server.cfg"); pisa_cfg_setup_file("co_server.cfg"); allowed = pisa_hitlist_build("allowed_hosts"); #ifdef CONFIG_PISA_WITH_HIPL hip_set_logdebug(1); /* disable the debug output from HIPL code */ #endif /* CONFIG_PISA_WITH_HIPL */ - sock = createServerSocket(); + sock = create_server_socket(); getDefaultHIT(&issuer_hit); - printf("community operator server ready\n"); + PISA_INFO("community operator server ready\n"); + + PISA_INFO("\nwaiting for incoming packet...\n"); + while (running) { + fd_set readfds; + struct timeval select_to; + + FD_ZERO(&readfds); + + select_to.tv_sec = 3; + select_to.tv_usec = 0; + + FD_SET(sock, &readfds); + + if (select(sock + 1, &readfds, NULL, NULL, &select_to) > 0) { + // Receive request + if (FD_ISSET(sock, &readfds)) { + addrlen = sizeof(cl_addr); + received = recvfrom(sock, packet, sizeof(co_packet), 0, + (struct sockaddr *) &cl_addr, &addrlen); + + if (received < 0) { + perror("error in recvfrom:"); + continue; + } else if (received == 0) + continue; + + inet_ntop(AF_INET6, &cl_addr.sin6_addr, addr_string, + INET6_ADDRSTRLEN); + PISA_DEBUG(PL_GENERIC, "received %i bytes from %s\n", received, + addr_string); + + if (pisa_ipv6_addr_is_hit(&cl_addr.sin6_addr)) { + PISA_DEBUG(PL_GENERIC, + "sender was a HIT, processing request.\n"); + handle_packet(&cl_addr, packet); + } else { + PISA_DEBUG(PL_GENERIC, + "sender was not a HIT, ignoring request.\n"); + } - while (1) { - printf("\nwaiting for incoming packet...\n"); - addrlen = sizeof(cl_addr); - received = recvfrom(sock, buf, BUFSIZE, 0, - (struct sockaddr *)&cl_addr, &addrlen); - - if (received < 0) { - perror("error in recvfrom:"); - continue; - } else if (received == 0) - continue; - - inet_ntop(AF_INET6, &cl_addr.sin6_addr, addr_string, - INET6_ADDRSTRLEN); - printf("received %i bytes from %s\n", received, addr_string); - - if (pisa_ipv6_addr_is_hit(&cl_addr.sin6_addr)) { - printf("sender was a HIT, processing request.\n"); - answerCertificateQuery(&cl_addr); - } else { - printf("sender was not a HIT, ignoring request.\n"); + PISA_INFO("\nwaiting for incoming packet...\n"); + } } } pisa_hitlist_destroy(allowed); pisa_cfg_cleanup(); - close(sock); - free(buf); + pisa_cfg_authorized_hosts_cleanup(); + free(packet); free(addr_string); + close(sock); return 0; } + +/** + * This function handles any packet received. + * + * @param socket_addr IP address where the packet was received + * @param co_packet A pointer to a co_packet_t structure + * + * @return 1 if successfully handled; 0 if packet unrecognized + */ +static int handle_packet(struct sockaddr_in6 *socket_addr, co_packet *packet) +{ + int result; + + assert(socket_addr != NULL); + assert(packet != NULL); + + switch (packet->message_type) { + case MESSAGE_CERTIFICATE_REQUEST: + result = answer_certificate_query(socket_addr); + break; + case MESSAGE_ERROR: + PISA_ERROR("Error: %i\n", packet->message.error.error_type); + result = 0; + break; + default: + result = 0; + break; + } + + return result; +}