[pisa-src] r1236 - in trunk/community-operator: Makefile.am co_client.c co_common_packets.h co_server.c

  • From: Jan Marten <jan.marten@xxxxxxxxxxxxxx>
  • To: pisa-src@xxxxxxxxxxxxx
  • Date: Mon, 19 Oct 2009 20:59:44 +0200

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(&not_before);
        time(&not_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(&not_before, &not_after, hit, &issuer_hit, cert,
                              CERT_BUF_SIZE) != 0) {
+#else
+       if (createCertificate(&not_before, &not_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;
+}

Other related posts: