Skip to content

Commit

Permalink
banners
Browse files Browse the repository at this point in the history
  • Loading branch information
robertdavidgraham committed Sep 11, 2013
1 parent b0dc06c commit 3216fe8
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 0 deletions.
158 changes: 158 additions & 0 deletions src/proto-http.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include "proto-banner1.h"
#include "smack.h"
#include <ctype.h>

enum {
HTTPFIELD_INCOMPLETE,
HTTPFIELD_SERVER,
HTTPFIELD_UNKNOWN,
HTTPFIELD_NEWLINE,
};
struct Patterns http_fields[] = {
{"Server:", 7, HTTPFIELD_SERVER, SMACK_ANCHOR_BEGIN},
{":", 1, HTTPFIELD_UNKNOWN, 0},
{"\n", 1, HTTPFIELD_NEWLINE, 0},
{0,0,0,0}
};




/***************************************************************************
* BIZARRE CODE ALERT!
*
* This uses a "byte-by-byte state-machine" to parse the response HTTP
* header. This is standard practice for high-performance network
* devices, but is probably unfamiliar to the average network engineer.
*
* The way this works is that each byte of input causes a transition to
* the next state. That means we can parse the response from a server
* without having to buffer packets. The server can send the response
* one byte at a time (one packet for each byte) or in one entire packet.
* Either way, we don't. We don't need to buffer the entire response
* header waiting for the final packet to arrive, but handle each packet
* individually.
*
* This is especially useful with our custom TCP stack, which simply
* rejects out-of-order packets.
***************************************************************************/
unsigned
banner_http( struct Banner1 *banner1,
unsigned state,
const unsigned char *px, size_t length,
char *banner, unsigned *banner_offset, size_t banner_max)
{
unsigned i;
unsigned state2;
size_t id;
enum {
FIELD_START = 9,
FIELD_NAME,
FIELD_COLON,
FIELD_VALUE,

};

state2 = (state>>16) & 0xFFFF;
id = (state>>8) & 0xFF;
state = (state>>0) & 0xFF;

for (i=0; i<length; i++)
switch (state) {
case 0: case 1: case 2: case 3: case 4:
if (toupper(px[i]) != "HTTP/"[state])
state = STATE_DONE;
else
state++;
break;
case 5:
if (px[i] == '.')
state++;
else if (!isdigit(px[i]))
state = STATE_DONE;
break;
case 6:
if (isspace(px[i]))
state++;
else if (!isdigit(px[i]))
state = STATE_DONE;
break;
case 7:
/* TODO: look for 1xx response code */
if (px[i] == '\n')
state = FIELD_START;
break;
case FIELD_START:
if (px[i] == '\r')
break;
else if (px[i] == '\n') {
state = STATE_DONE;
break;
} else {
state2 = 0;
state = FIELD_NAME;
/* drop down */
}

case FIELD_NAME:
if (px[i] == '\r')
break;
id = smack_search_next(
banner1->http_fields,
&state2,
px, &i, (unsigned)length);
if (id == HTTPFIELD_NEWLINE) {
state2 = 0;
state = FIELD_START;
} else if (id == SMACK_NOT_FOUND)
; /* continue here */
else if (id == HTTPFIELD_UNKNOWN) {
size_t id2;

id2 = smack_next_match(banner1->http_fields, &state2);
if (id2 != SMACK_NOT_FOUND)
id = id2;

state = FIELD_COLON;
} else
state = STATE_DONE;
break;
case FIELD_COLON:
if (px[i] == '\n') {
state = FIELD_START;
break;
} else if (isspace(px[i])) {
break;
} else {
state = FIELD_VALUE;
/* drop down */
}

case FIELD_VALUE:
if (px[i] == '\r')
break;
else if (px[i] == '\n') {
state = FIELD_START;
break;
}
if (id == HTTPFIELD_SERVER) {
if (*banner_offset < banner_max) {
banner[(*banner_offset)++] = px[i];
}
}
break;

case STATE_DONE:
default:
i = (unsigned)length;
break;
}


if (state == STATE_DONE)
return state;
else
return (state2 & 0xFFFF) << 16
| (id & 0xFF) << 8
| (state & 0xFF);
}
15 changes: 15 additions & 0 deletions src/proto-http.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef PROTO_HTTP_H
#define PROTO_HTTP_H
#include "proto-banner1.h"

extern struct Patterns http_fields[];


unsigned
banner_http( struct Banner1 *banner1,
unsigned state,
const unsigned char *px, size_t length,
char *banner, unsigned *banner_offset, size_t banner_max);

#endif

34 changes: 34 additions & 0 deletions src/proto-ssh.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "proto-ssh.h"
#include "proto-banner1.h"
#include <ctype.h>

/***************************************************************************
***************************************************************************/
unsigned
banner_ssh( struct Banner1 *banner1,
unsigned state,
const unsigned char *px, size_t length,
char *banner, unsigned *banner_offset, size_t banner_max)
{
unsigned i;

banner1=banner1;

for (i=0; i<length; i++)
switch (state) {
case 0:
if (px[i] == '\r')
continue;
if (px[i] == '\n' || px[i] == '\0' || !isprint(px[i])) {
state = STATE_DONE;
continue;
}
if (*banner_offset < banner_max)
banner[(*banner_offset)++] = px[i];
break;
default:
i = (unsigned)length;
break;
}
return state;
}
11 changes: 11 additions & 0 deletions src/proto-ssh.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef PROTO_SSH_H
#define PROTO_SSH_H
struct Banner1;

unsigned
banner_ssh( struct Banner1 *banner1,
unsigned state,
const unsigned char *px, size_t length,
char *banner, unsigned *banner_offset, size_t banner_max);

#endif

0 comments on commit 3216fe8

Please sign in to comment.