Showing posts with label software development. Show all posts
Showing posts with label software development. Show all posts

Monday, August 5, 2013

Simple TCP Server in C - Republish

Security Note

If you need to set up a command server, there are a few issues. The first and foremost is security, though in the contexts of this document we will fore go the security issues. In this document we will discuss the ability to set up and create a simple server using unix and C/C++, leaving the discussion of securing a simple command server to a different document.

First, please be aware that running the resulting server as a root account could cause potential damage to the system (via hackers). So, this is only documented as research, with no liabilities held by the authors, consultants, or companies holding this code specifically as such.

Constructing the Program

First, we need to understand how a TCP/IP server even works. When a message is sent from a client to a server, it is encoded with an ID number, or a port as commonly referred to. Some port numbers are associated with a name, such as www (80), telnet (21), ssh (23), and SMTP/Mail (25). These are referred to as "common" ports. We need to identify the best port (preferrably one that is not used in any circumstances). I like to use the port 666 for software like this as it can be a real devil to secure. You will note that, in unix systems, one must be the root user in order to use privileged ports (ports under 1000), just to ensure the safety and well being of the "common" ports.

On the server itself, a piece of software called a daemon is running, and listening for connections that have the specified ID/port. When one comes in, it can then accept these connections, and recieve and transmit data to/from the other end of the connection (client).

An endpoint for TCP/IP communication is called a socket. The header file is called "sys/socket.h" (except in MS Windows where it is "winsock.h"). We will create a socket handle, using the socket function. Rather than opening the socket (a client will do this), bind to the socket, listen for incoming connections, and then accept them.

socket : This creates an endpoint, or a socket, to communicate with a client or a server on the network. It's use is :

int socket(int domain, int type, int protocol);

The integer returned is the handle to our socket.

bind : bind assigns the local port and server address to the socket. When a socket is created with the above socket command, it is classed only as a family (TCP is the AF_INET family, or internet type of socket). This can be used to request that a specific IP address will be listened to, or any IP address on the machine. The code :

int bind(int s, const struct sockaddr *addr, socklen_t addrlen);

listen : listen tells the program that incoming connections will be used. It also allows you to set things like queue limits for connections that clients have requested.

int listen(int s, int queued_connections);

accept : Once a socket has been created, assigned a port, and is listening for connections, you must call accept. Accept will block (meaning that it will wait until a connection request is made).

int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

Creating the Source Code

We'll save the topic for creating a Makefile for a completely different discussion, as this can get extremely complex. In the mean time, use the following :
    # Makefile for a simple TCP Server
    
    PROGRAM =tcp_server
    CC      =gcc
    CCF     =-c
    LINKER  =ld
    LINKERF =-lc /usr/lib/crt1.o
    SRCS    =\
            main
    OBJS    =
    CCSRCS  =
    
    .for SRC in $(SRCS)
      OBJS += $(SRC).o
    .endfor
    
    all: compile link
    
    $(SRCS) :
            $(CC) $(CCF) $@.c -o $@.o
    
    compile: $(SRCS)
    
    link:
            $(LINKER) $(LINKERF) $(OBJS) -o $(PROGRAM)
    
    rmproper: clean
    
    clean:
            @rm *.o
            @rm $(PROGRAM)
    
Now, with this Makefile, all we will ever need to be worried about is adding source modules to the SRCS parameter (which already has a tcp and a main). The backslash is an escape method of saying "we're still adding stuff to the variable using the next line of information".

Okay, we need to have a 'main' function. The purpose of a 'main' function is to provide a uniform method for all C programs to be compiled. So, we create our function, and make it call our server code. If you want to add the ability to use command line options as you'll find on most tcp servers, this is the function you would add the code to. But, since all we need to do is start our TCP server, our function will be short :
    int main(void) {
            start_server(); /* start the tcp server */
            return 0;       /* return "success" to the shell */
    }
    
Nice and simple, eh? In fact, if you commented out that start_server(); line, and replace it with a printf("Hello, World!");, and you've got yourself the infamous "Hello, World!" program that is taught as the first step in C Programming.

But that's not what we're after. We are going to assemble a simple TCP command server. So, we leave the start_server(); line in place, and add a function called start_server(). It should take no parameters, because our example program is purely designed to be as simple as can be.

Prior to performing any socket operations, we will need to make sure we've got the right headers. Of we don't, compiling will fail the program. The headers we'll need are :
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <netdb.h>
    
Once you've got those, the following functions should be okay.

Inside of the function, we will need to create and prepare our socket. First, we create the socket handle (which is an integer) by creating an integer variable and assigning to it the result of calling the socket(AF_INET,SOCK_STREAM,getprotobyname("tcp")). The AF_INET declaration is specifically for the Internet, and the SOCK_STREAM number for the type is required for TCP data. We can typecast the return value of the getprotobyname to int just to keep from getting a lot of warning messages. But, here in our example, we'll just use 0 for that.

Once we have the socket handle created and initialized, we then bind the socket address information to our new socket handle. We first fill out the socket information, setting the address to the IP we are going to bind to (INADDR_ANY if we want to open up to any IP address), and also set the socket's family (the AF_INET is used twice, once for the operating system using the connect function call, and once for the socket information itself). We then push these parameters into the socket information using the bind() function, as in :

bind(our_socket_handle,(struct sockaddr *)&socket_info,sizeof(socket_info)).

Now, before proceding, I MUST hit on a key programming factor. ALWAYS check the status of a function if it returns it. The last thing you need to do is try a function call on an already defunct socket handle. So, PLEASE check the status of the bind function.
    int start_server(void) {
     int                  our_socket_handle,status;
     struct sockaddr_in   socket_info;
    
     our_socket_handle = socket(AF_INET,SOCK_STREAM,0);
     if (our_socket_handle == -1) {
      perror("Creating socket()");
      exit(1);
     }
    
     socket_info.sin_family      = AF_INET;              /* Internet TCP/IP              */
     socket_info.sin_addr.s_addr = htonl(INADDR_ANY);    /* listen on any IP address     */
     socket_info.sin_port        = htons(5000);          /* 5000 is an unprivileged port */
    
     status = bind(our_socket_handle,(struct sockaddr *)&socket_info,sizeof(struct sockaddr));
     if (status) {
      fprintf(stderr,"Cannot bind() to the socket");
      exit(1);
     }
    }
    
Now, we've bound the socket's information to it, so we need to listen() and accept() connections. Here's how we do that.

Listen is a straight forward function. All it is designed to do is tell the operating system that we are waiting for connections on the socket. We also include the number of back logged, or queued connections that we will allow to wait for our program (in this example, we'' listen for 5 connections), e.g. :

status = listen(our_socket_handle,5);.

Then we put a loop function around the accept() function. This allows us to retrieve an unlimited number of connections (though still at one at a time). But, since this is a simple tutorial, we will NOT put the accept in a loop. All we will do is retrieve the information that is sent, send it back, and exit. It's primarily a simple procedure to test with.

This accept() function is designed to recieve a connection. It will block until a connection is recieved, then proceed to the next line of code. It initializes a socket structure with the clients connection, and then releases you to work. Don't forget that the return variable, client_socket_handle, needs to be declared in the variables at the top. We also add the client_socket_info structure, and we're ready to implement it. Also, don't forget to close the sockets :
    status = listen(our_socket_handle,5); if (status) { fprintf(stderr,"Cannot listen() to socket"); exit(1); } client_socket_handle = accept(our_socket_handle,(struct sockaddr *)&client_socket_info,sizeof(struct sockaddr)); write(client_socket_handle,"Hello, World!",strlen("Hello, World!")); close(client_socket_handle); close(our_socket_handle);
Now, with this entire program, if you were to run it, it should not give you the command prompt back. Now, open up another telnet window, and go to the server you are running this on, at port 5000, and you should get an immediate close of the connection, but it should have printed the "Hello, World!" string before closing. Pretty snazzy, eh? Using a combination of the send() and recv() functions, you can build an effective communication tool to do nearly anything you need. Effectively, here is our main.c file :
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    
    int main(void) {
     start_server(); /* start the tcp server */
     return 0; /* return "success" to the shell */
    }
    
    int start_server(void) {
     int                  our_socket_handle,client_socket_handle,socket_size,status;
     struct sockaddr_in   socket_info;
     struct sockaddr_in   client_socket_info;
    
     our_socket_handle = socket(AF_INET,SOCK_STREAM,0); //(int)getprotobyname("tcp"));
     if (our_socket_handle == -1) {
      perror("Cannot create the socket : ");
      exit(1);
     }
    
     socket_info.sin_family = AF_INET;
     socket_info.sin_addr.s_addr = htonl(INADDR_ANY);
     socket_info.sin_port = htons(5000);
    
     status = bind(our_socket_handle,(struct sockaddr*)&socket_info,sizeof(struct sockaddr));
     if (status == -1) {
      perror("Cannot bind() to socket : ");
      exit(1);
     }
    
     status = listen(our_socket_handle,5);
     if (status == -1) {
      fprintf(stderr,"Cannot listen() to socket");
      exit(1);
     }
    
     socket_size = sizeof(struct sockaddr);
     client_socket_handle = accept(our_socket_handle,(struct sockaddr *)&client_socket_info,&socket_size);
     write(client_socket_handle,"HELLO, WORLD!",strlen("HELLO, WORLD!"));
     close(client_socket_handle);
     close(our_socket_handle);
    };
    

Friday, July 26, 2013

Apache Module Config Merge

An example apache module merge routine :
    
    static void *mod_gzip_merge_dconfig(
    apr_pool_t *p,
    void *parent_conf,
    void *newloc_conf
    )
    {
     mod_gzip_conf *merged_config = (mod_gzip_conf *) apr_pcalloc(p, sizeof(mod_gzip_conf));
     mod_gzip_conf *pconf         = (mod_gzip_conf *) parent_conf;
     mod_gzip_conf *nconf         = (mod_gzip_conf *) newloc_conf;
    
     mod_gzip_merge1(
     ( apr_pool_t    * ) p,
     ( mod_gzip_conf * ) merged_config,
     ( mod_gzip_conf * ) pconf,
     ( mod_gzip_conf * ) nconf
     );
    
    
    
    static int mod_gzip_handler( request_rec *r ) {
     mod_gzip_conf *mgc; /* Location/Directory configuration */
     mgc = ( mod_gzip_conf * )
     ap_get_module_config( r->per_dir_config, &gzip_module );
    }
    
    register_hooks() {
      ap_hook_insert_filter( mod_gzip_insert_output_filter, NULL, NULL, APR_HOOK_MIDDLE );
     ap_register_output_filter( mod_gzip_filter_name, mod_gzip_output_filter, AP_FTYPE_CONTENT );
     return;
    }
    

Java - Multithreading Example

An old example of threading in Java (Java doesn't natively support fork() ) :
    
    import java.lang.Thread;
    import java.lang.System;
    import java.lang.Math;
    import java.lang.InterruptedException;
    import java.lang.Runnable;
    
    class ThreadTest2 {
     public static void main(String args[]) {
      Thread thread1 = new Thread(new MyClass("thread1: "));
      Thread thread2 = new Thread(new MyClass("thread2: "));
      thread1.start();
      thread2.start();
      boolean thread1IsAlive = true;
      boolean thread2IsAlive = true;
      do {
       if(thread1IsAlive && !thread1.isAlive()){
        thread1IsAlive = false;
        System.out.println("Thread 1 is dead.");
       }
       if(thread2IsAlive && !thread2.isAlive()){
        thread2IsAlive = false;
        System.out.println("Thread 2 is dead.");
       }
      }while(thread1IsAlive || thread2IsAlive);
     }
    }
    class MyClass implements Runnable {
     static String message[] = {"Java","is","hot,","aromatic,","and",
      "invigorating."};
     String name;
     public MyClass(String id) {
      name = id;
     }
     public void run() {
      for(int i=0;<message.length;++i) {
       randomWait();
       System.out.println(name+message[i]);
      }
     }
     void randomWait(){
      try {
       Thread.currentThread().sleep((long)(3000*Math.random()));
      }catch (InterruptedException x){
       System.out.println("Interrupted!");
      }
     }
    }
    

Including a Request Via Apache Module

The first step in including another URL into an apache request is to create an output filter that simply does nothing but append the content to a variable. This filter must not be registered except in very specific circumstances.

Please note that this function is copied directly from some private code. The ((template_context *)f->ctx) variable is a standard filter context variable that is typecast to what I know it is, which contains an apr_bucket, etc (and my variable that includes the output of the "include"). The structure (so you can know what type the variables are) will be at the bottom of this document. The function :
    
    static apr_status_t mod_template_include_output_filter(ap_filter_t *f, apr_bucket_brigade *bb) {
    
      for (((template_context *)f->ctx)->include_bucket = APR_BRIGADE_FIRST(bb);
          ((template_context *)f->ctx)->include_bucket != APR_BRIGADE_SENTINEL(bb);
          ((template_context *)f->ctx)->include_bucket = APR_BUCKET_NEXT(((template_context *)f->ctx)->include_bucket)) {    if (!APR_BUCKET_IS_EOS(((template_context *)f->ctx)->include_bucket)) {
          if (apr_bucket_read(((template_context *)f->ctx)->include_bucket,&(((template_context *)f->ctx)->include_data),&(((template_context *)f->ctx)->include_length),APR_BLOCK_READ) == APR_SUCCESS) {
            if (((template_context *)f->ctx)->include_data_real == NULL) {
              ((template_context *)f->ctx)->include_data_real = apr_palloc(f->r->pool,((template_context *)f->ctx)->include_length+1);
              strncpy(((template_context *)f->ctx)->include_data_real,((template_context *)f->ctx)->include_data,((template_context *)f->ctx)->include_length);
              ((template_context *)f->ctx)->include_data_real[((template_context *)f->ctx)->include_length] = '\0';
            } else {
              ((template_context *)f->ctx)->include_data_tmp = ((template_context *)f->ctx)->include_data_real;
              ((template_context *)f->ctx)->include_data_real = apr_palloc(f->r->pool,((template_context *)f->ctx)->include_length+strlen(((template_context *)f->ctx)->include_data_tmp) + 1);
              strcpy(((template_context *)f->ctx)->include_data_real,((template_context *)f->ctx)->include_data_tmp);
              strncat(((template_context *)f->ctx)->include_data_real,((template_context *)f->ctx)->include_data,((template_context *)f->ctx)->include_length);
              ((template_context *)f->ctx)->include_data_real[((template_context *)f->ctx)->include_length+strlen(((template_context *)f->ctx)->include_data_tmp)] = '\0';
            }
            APR_BUCKET_REMOVE(((template_context *)f->ctx)->include_bucket);
          }
        }
      };
      apr_brigade_destroy(bb);
      return APR_SUCCESS;
      //return apr_brigade_create(f->r->pool,f->c->bucket_alloc);
    }
    
    

The next step is to actually call a sub request, assign the filter to it, and run it. First, I set up the request doing this :

    
    ((template_context *)f->ctx)->include_filter_rec = apr_palloc(f->r->pool,sizeof(ap_filter_rec_t));
      memset(((template_context *)f->ctx)->include_filter_rec,0,sizeof(ap_filter_rec_t));
      ((template_context *)f->ctx)->include_filter_rec->name = "TEMPLATE-INCLUDE-WRAPPER";
      ((template_context *)f->ctx)->include_filter_rec->filter_func.out_func = &mod_template_include_output_filter;
      ((template_context *)f->ctx)->include_filter_rec->next = NULL;
      ((template_context *)f->ctx)->include_filter_rec->ftype = AP_FTYPE_RESOURCE;
    
      ((template_context *)f->ctx)->include_filter = apr_palloc(f->r->pool,sizeof(ap_filter_t));
      ((template_context *)f->ctx)->include_filter->frec = ((template_context *)f->ctx)->include_filter_rec;
      ((template_context *)f->ctx)->include_filter->ctx = (template_context *)f->ctx;
      ((template_context *)f->ctx)->include_filter->next = NULL;
      ((template_context *)f->ctx)->include_filter->r = f->r;
      ((template_context *)f->ctx)->include_filter->c = f->r->connection;
    
    

Next, I run the request using :

    
    /* now, run the subrequest */
      ((template_context *)f->ctx)->include_data = NULL;
      ((template_context *)f->ctx)->include_data_real = NULL;
      ((template_context *)f->ctx)->include_r = ap_sub_req_lookup_uri(uri,f->r,((template_context *)f->ctx)->include_filter);
      if ((((template_context *)f->ctx)->include_r != NULL) && (((template_context *)f->ctx)->include_r->status == HTTP_OK)) {
        ((template_context *)f->ctx)->include_int = ap_run_sub_req(((template_context *)f->ctx)->include_r);
      }
      if (((template_context *)f->ctx)->include_r != NULL) {
        ap_destroy_sub_req(((template_context *)f->ctx)->include_r);
      }
    

Now, just to be sure, check the results - if there was an error, you may not want that in the document. For example :

    
    /* did we have an error of sorts? */
      if (((template_context *)f->ctx)->include_data_real == NULL) {
        return NULL;
      }
    
    

Then you can create a new bucket (with a filter) or just respond with the handler using the fresh content :

    
    new_bucket = apr_bucket_pool_create(((template_context *)f->ctx)->include_data_real,strlen(((template_context *)f->ctx)->include_data_real),f->r->pool,f->c->bucket_alloc);
    
    

Now, for those that have waited patiently, the following is the structure definition of my context :

    
    typedef struct template_context {
      char                          *title;
      char                          *head;
      const char                    *include_data;
      char                          *include_data_tmp;
      char                          *include_data_real;
      apr_bucket                    *include_bucket;
    //  apr_off_t                   include_length;
      apr_ssize_t                   include_length;
      ap_filter_rec_t               *include_filter_rec;
      ap_filter_t                   *include_filter;
      int                           include_int;
      request_rec                   *include_r;
      const char                    *header;
      const char                    *trailer;
      const char                    *bucket_data;
      apr_file_t                    *f_header;
      apr_file_t                    *f_trailer;
      apr_file_t                    *file_tmp;
      apr_finfo_t                   sb;
      char                          *buffer;
      char                          *char_tmp;
      int                           get_tag_length;
      int                           int_tmp;
      int                           content_length;
      char                          *tag_open;
      char                          *tag_close;
      int                           flags;
      struct content_type_list      *types;
      const apr_strmatch_pattern    *strmatch;
      const char                    *match;
      apr_bucket_brigade            *brigade;
      apr_bucket                    *trailer_bucket;
      apr_size_t                    bucket_length;
      apr_bucket                    *current_bucket;
      apr_bucket                    *tmp_bucket;
      apr_bucket                    *new_bucket;
      apr_time_t                    time_tmp;
      template_conf                 *config;
    } template_context;
    

Yes, it will be a little obvious that my template wrapping module is fairly complex, but that is okay - it does a great deal more than just wrapping. It adjusts modified dates/times based on the template, it uses includes, finding additional components (dynamic menu building, etc). And all done on the fly. It was a very fun project to build!

Tuesday, February 19, 2013

Application Signing with Mono

I spent the weekend writing a Winblows... a Windoze... a WindOWS application (sorry, that's hard for me to do because I'm an opensource kind of guy, and really don't use Windows much).  See, I had this problem of having an old Windows Vista Home PC without the ability to automatically store new files onto a NAS that could then be edited on a Macbook Pro and automatically be ready for edit back on the Windows box (before you give me spiels about "use sharing" - the Windows computer is not on all the time, and with Vista Home, you can't change those locations to be a network share from a NAS - trust me, I tried and failed miserably).

In the process, I wrote a simply application for Wingoes that monitors specific directories (I made it configurable so you can easily control it).  Since I didn't want to download a WinPose SDK kit, I wrote and compiled the Winhose thing using Mono - and ran into a problem I couldn't find an easy solution to : signing the resulting .EXE application.  I did manage to figure it out after a few hours, though.  Here's how I did it.

  1. Ensure you have the mono-devel package installed.  Up to this point, I had a working application without the mono-devel package.  It provides a nice binary called "signtool".  e.g.

    yum install mono-devel
  2. Next, create a new certificate authority configuration file.  It can be almost identical to your regular signing CA with one change - in the "[ server_cert ]" section, change "extendedKeyUsage" to a value of "codeSigning", and possibly generate new keys and configure them in the file.  I generated new keys for this one :

    cd /etc/pki/tls/
    openssl genrsa -des3 -out private/signing.key 4096

    openssl req -new -x509 -days 3650 -key private/signing.key -out certs/signing.crt
  3. Create your own signing request and key :

    openssl req -newkey rsa:1024 -nodes -out silverhawk-codesign.csr -keyout silverhawk-codesign.key
  4. Sign your certificate :

    openssl ca -batch -config /etc/pki/tls/signing.conf -notext -in silverhawk-codesign.csr -out silverhawk-codesign.crt

  5. I then exported the files into various formats just in case they are needed down the road.  Please keep these secure!  My formatting options :

    openssl pkcs12 -export -out silverhawk-codesign.pfx -inkey silverhawk-codesign.key -in silverhawk-codesign.crt
    openssl pkcs12 -in silverhawk-codesign.pfx -out silverhawk-codesign.pem -nodes

    openssl rsa -in silverhawk-codesign.key -outform PVK -pvk-strong -out silverhawk-codesign.pvk

    openssl crl2pkcs7 -nocrl -certfile silverhawk-codesign.crt -outform DER -out silverhawk-codesign.spc

     
  6. Next, you can finally sign the application :

    signcode -spc /path/to/created/silverhawk-codesign.spc -v /path/to/created/silverhawk-codesign.pvk -a sha1 -$ commercial -n "SilverSync" -i http://www.silverhawk.net/ -t http://timestamp.verisign.com/scripts/timstamp.dll -tr 10 SilverSync.exe
This finally allowed my to save firewall information on the application when it ran.  Hooray!

Thursday, June 16, 2011

Testing is for the Birds

Being a systems administrator, I often get to see developers and team leads run into the operations center under the gun (news to the admins) that they have been getting pressure for a while to fix their application.

Most recently (this morning), a team lead for a group of developers came in, trying to figure out why it was broken. So we dug into the logs. It's a java app, so it uses log4j as the logger, making it nice and easy to see the problem.

Clearly, in the log file, I see a message similar to "we are creating file /application/work/datafile.xml". It is followed up with a line about it transferring the file to another location. That is followed by a stack trace, clearly showing that it failed to transfer a zero byte file "application/datafile.xml".

How did the application make it through testing? It's not even the same directory. In one instance, it's "/application/work", but in the next, it is "/application".

Do we really feel like we shouldn't test? [sigh].