Home

Traffic Server Software Developers Kit

Appendix A. Sample Source Code

Table of Contents

blacklist-1.c

This appendix provides several source code examples. In the online formats of this book, function calls are linked to their references in the previous chapters. The following sample plugins are provided:

blacklist-1.c

The sample blacklisting plugin included in the Traffic Server SDK is blacklist-1.c. This plugin checks every incoming HTTP client request against a list of blacklisted web sites. If the client requests a blacklisted site, then the plugin returns an Access forbidden message to the client.

This plugin illustrates:

  • An HTTP transaction extension

  • How to examine HTTP request headers

  • How to use the logging interface

  • How to use the plugin configuration management interface

/* blacklist-1.c:  an example program that denies client access                 
 *                 to blacklisted sites. This plugin illustrates
 *                 how to use configuration information from a 
 *                 configuration file (blacklist.txt).
 *
 * Usage:    
 * (Solaris) : blacklist-1.so 
 *
 *
 */

#include <stdio.h>
#include <string.h>
#include "InkAPI.h"

#define MAX_NSITES 500

static char* sites[MAX_NSITES];
static int nsites;
static INKMutex sites_mutex;
static INKTextLogObject log;

static void
handle_dns (INKHttpTxn txnp, INKCont contp)
{
    INKMBuffer bufp;
    INKMLoc hdr_loc;
    INKMLoc url_loc;
    const char *host;
    int i;
    int host_length;
    
    if (!INKHttpTxnClientReqGet (txnp, &bufp, &hdr_loc)) {
        INKError ("couldn't retrieve client request header\n");
        goto done;
    }
    
    url_loc = INKHttpHdrUrlGet (bufp, hdr_loc);
    if (!url_loc) {
        INKError ("couldn't retrieve request url\n");
        INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
        goto done;
    }
    
    host = INKUrlHostGet (bufp, url_loc, &host_length);
    if (!host) {
        INKError ("couldn't retrieve request hostname\n");
        INKHandleMLocRelease (bufp, hdr_loc, url_loc);
        INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
        goto done;
    }

    INKMutexLock(sites_mutex);

    for (i = 0; i < nsites; i++) {
        if (strncmp (host, sites[i], host_length) == 0) {
       if (log) {
      INKTextLogObjectWrite(log, "blacklisting site: %s", sites[i]);
       } else {
      printf ("blacklisting site: %s\n", sites[i]);
       }
            INKHttpTxnHookAdd (txnp,
                INK_HTTP_SEND_RESPONSE_HDR_HOOK,
                contp);
            INKHandleStringRelease (bufp, url_loc, host);
            INKHandleMLocRelease (bufp, hdr_loc, url_loc);
            INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
            INKHttpTxnReenable (txnp, INK_EVENT_HTTP_ERROR);
       INKMutexUnlock(sites_mutex);
            return;
        }
    }

    INKMutexUnlock(sites_mutex);
    INKHandleStringRelease (bufp, url_loc, host);
    INKHandleMLocRelease (bufp, hdr_loc, url_loc);
    INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);

 done:
    INKHttpTxnReenable (txnp, INK_EVENT_HTTP_CONTINUE);
}

static void
handle_response (INKHttpTxn txnp)
{
    INKMBuffer bufp;
    INKMLoc hdr_loc;
    INKMLoc url_loc;
    char *url_str;
    char *buf;
    int url_length;
 
    if (!INKHttpTxnClientRespGet (txnp, &bufp, &hdr_loc)) {
        INKError ("couldn't retrieve client response header\n");
        goto done;
    }
    
    INKHttpHdrStatusSet (bufp, hdr_loc, INK_HTTP_STATUS_FORBIDDEN);
    INKHttpHdrReasonSet (bufp, hdr_loc,
        INKHttpHdrReasonLookup (INK_HTTP_STATUS_FORBIDDEN), 
        strlen (INKHttpHdrReasonLookup (INK_HTTP_STATUS_FORBIDDEN)) );
    
    if (!INKHttpTxnClientReqGet (txnp, &bufp, &hdr_loc)) {
        INKError ("couldn't retrieve client request header\n");
        INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
        goto done;
    }
    
    url_loc = INKHttpHdrUrlGet (bufp, hdr_loc);
    if (!url_loc) {
        INKError ("couldn't retrieve request url\n");
        INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
        goto done;
    }
    
    buf = (char *)INKmalloc (4096);
    
    url_str = INKUrlStringGet (bufp, url_loc, &url_length);
    sprintf (buf, "You are forbidden from accessing \"%s\"\n", url_str);
    INKfree (url_str);
    INKHandleMLocRelease (bufp, hdr_loc, url_loc);
    INKHandleMLocRelease (bufp, INK_NULL_MLOC, hdr_loc);
  
    INKHttpTxnErrorBodySet (txnp, buf, strlen (buf), NULL);

 done:
    INKHttpTxnReenable (txnp, INK_EVENT_HTTP_CONTINUE);
}

static void
read_blacklist (void)
{
    char blacklist_file[1024];
    INKFile file;

    sprintf (blacklist_file, "%s/blacklist.txt", INKPluginDirGet());
    file = INKfopen(blacklist_file, "r");

    INKMutexLock (sites_mutex);
    nsites = 0;

    if (file != NULL) {
   char buffer[1024];

   while (INKfgets (file, buffer, sizeof(buffer)-1) != NULL &&
          nsites < MAX_NSITES) {
       char* eol;
       if ((eol = strstr(buffer, "\r\n")) != NULL) {
      /* To handle newlines on Windows */
      *eol = '\0';
       } else if ((eol = strchr(buffer, '\n')) != NULL) {
      *eol = '\0';
       } else {
      /* Not a valid line, skip it */
      continue;
       }
       if (sites[nsites] != NULL) {
      INKfree (sites[nsites]);
       }
       sites[nsites] = INKstrdup (buffer);
       nsites++;
   }

   INKfclose (file);
    } else {
   INKError ("unable to open %s\n", blacklist_file);
   INKError ("all sites will be allowed\n", blacklist_file);
    }
   
    INKMutexUnlock (sites_mutex);

}

static int
blacklist_plugin (INKCont contp, INKEvent event, void *edata)
{
    INKHttpTxn txnp = (INKHttpTxn) edata;
    
    switch (event) {
    case INK_EVENT_HTTP_OS_DNS: 
        handle_dns (txnp, contp);
        return 0;
    case INK_EVENT_HTTP_SEND_RESPONSE_HDR:
        handle_response (txnp);
        return 0;
    case INK_EVENT_MGMT_UPDATE:
   read_blacklist ();
   return 0;
    default:
        break;
    }
    return 0;
}

int
check_ts_version() {

   const char* ts_version = INKTrafficServerVersionGet();
   int result = 0;

   if (ts_version) {
       int major_ts_version = 0;
       int minor_ts_version = 0;
       int patch_ts_version = 0;

       if (sscanf(ts_version, "%d.%d.%d", &major_ts_version,
        &minor_ts_version, &patch_ts_version) != 3) {
      return 0;
       }

       /* Since this is an TS-SDK 2.0 plugin, we need at
     least Traffic Server 3.5.2 to run */
       if (major_ts_version > 3) {
      result = 1;
       } else if (major_ts_version == 3) {
      if (minor_ts_version > 5) {
          result = 1;
      } else if (minor_ts_version == 5) {
          if (patch_ts_version >= 2) {
         result = 1;
          }
      }
       }
   }

   return result;
}

void
INKPluginInit (int argc, const char *argv[])
{
    int i;
    INKCont contp;
    INKPluginRegistrationInfo info;
    int error;
  
    info.plugin_name = "blacklist-1";
    info.vendor_name = "DsCompany";
    info.support_email = "ts-api-support@DsCompany.com";

    if (!INKPluginRegister (INK_SDK_VERSION_2_0 , &info)) {
        INKError ("Plugin registration failed.\n"); 
    }

    if (!check_ts_version()) {
   INKError ("Plugin requires Traffic Server 3.5.2 or later\n");
   return;
    }

    /* create an INKTextLogObject to log blacklisted requests to */
    log = INKTextLogObjectCreate("blacklist", INK_LOG_MODE_ADD_TIMESTAMP,
             NULL, &error);
    if (!log) {
   printf("Blacklist plugin: error %d while creating log\n", error);
    }

    sites_mutex = INKMutexCreate ();

    nsites = 0;
    for (i = 0; i < MAX_NSITES; i++) {
   sites[i] = NULL;
    }

    read_blacklist ();

    contp = INKContCreate (blacklist_plugin, NULL);
        
    INKHttpHookAdd (INK_HTTP_OS_DNS_HOOK, contp);

    INKMgmtUpdateRegister (contp, "Super Blacklist Plugin", "blacklist.cgi");
}