Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dreamhack changes #1

Merged
merged 7 commits into from Jan 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Expand Up @@ -52,6 +52,7 @@ Trunk all of your VLANs to a PC somewhere. (Consult switch documentation)
* -a : Listen on all PCAP supported interfaces (except USB and "any")
* -r : Enable rate limiting per source IP+destination UDP port combination
* -t nnn : Set rate limiter to nnn ms. Defaults to 1000ms. Implies -r
* -l : Turns on Stat logging (log RX/TX/DROP Packets to stats.log)
* -d : Turns on debug (doesn't do much yet
* -h : Shows this help

Expand Down Expand Up @@ -122,9 +123,15 @@ Your program might have a serious case of the bad programmer, and cannot deal wi

### What has this been used for?

We _finally_ used this at an event - PAX Aus 2016 PC area.
**PAX Aus 2016 PC area**
>We _finally_ used this at an event - PAX Aus 2016 PC area.
>
>it seemed to work pretty well. One VLAN apparently had some trouble discovering servers, but I did not get to investigate at the time, >so can't rule out individual PC problems, switch misconfiguration or bug in the application.

**DREAMHACK Ger 2016 LAN area**
> We used it at DHDE17 too. 1.500 users run very well on a enabled rate limiting at -t 750.
> Tested and added several games to the ports, after adding a bunch of ports the SDH crashed on memory exhaust but could be fixed by enabling the pcap optimized compile in code.

it seemed to work pretty well. One VLAN apparently had some trouble discovering servers, but I did not get to investigate at the time, so can't rule out individual PC problems, switch misconfiguration or bug in the application.

### To do list

Expand Down
28 changes: 23 additions & 5 deletions ports
Expand Up @@ -16,7 +16,10 @@
2470

# Blur
50001
#50001

# FlatOut 2
23757

# OpenTTD (not working atm)
# 3979
Expand All @@ -26,6 +29,9 @@
27015-27020
27005

# Rainbow Six Siege (untested)
3074

# Other ports Steam searches
26900-26905
4242
Expand All @@ -34,12 +40,24 @@
# (trackmania 2, shootmania)
2350-2360

# UT99 / Classic (tested at dreamhack)
8777-8786

# UT2004
10777

# Warcraft 3
# I recall starcraft also using this port. Will verify later.
6112
# Q3 Arena (tested at dreamhack)
27960-27963

# Warsow
# Blizzard Classics; (tested at dreamhack: wc3, sc1, d2)
6111
6112

# Warsow (tested at dreamhack)
44400

# Call of Duty 2/4 (tested at dreamhack)
28960-28963

# Blobby Volley (tested at dreamhack)
47624
77 changes: 62 additions & 15 deletions sdh-proxy.c
Expand Up @@ -65,9 +65,18 @@ int do_exit = 0;
// Toggled with -d on command line. Displays debug info.
int debug = 0;

// Toggled with -l on command line. Write Stats to stat.log
int logstat = 0;
char logstatfile[] = "sdh.stat";

// Does nothing at the moment. Will enable rewriting subnet info if relevant.
int do_network_rewrite = 0; // Rewrite IP broadcast address for the new
// network interface
int64_t pkt_rx = 0;
int64_t pkt_tx = 0;
int64_t pkt_drop = 0;
unsigned short int pkt_stats[65535];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for this - I expect the short would overflow pretty regularly? Maybe in the future we should make this a hash table so we don't need a giant array of mostly 0s, or somehow index the array based on the ports listed in the ports file. Not important though, just thinking out loud

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, indeed on the event the counter overflow several times, especially 27015 :)
For my purpose it was ok because I just tracked difference between previeous poll in a 10s resolution. But could be changed to int64

int logtimer = 0;

/**
* Calculate checksum for IP packet.
Expand Down Expand Up @@ -136,6 +145,37 @@ unsigned short int * udp_get_port( const short unsigned int pktlen, const u_char

}

/**
* function to log some statistical Ouitput to a logfile
* This is usefull to get somewhat of information / statistical logging.
*

*
**/
void writeLogStats()
{
// don't spam! just write the log once every X seconds
if((logtimer + 10) < (int)time(NULL)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is missing the value being update after each loop (eg, logtimer = time(NULL)), so this will run every time a packet is forwarded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it is missing but somehow it run correctly :) Will check.

FILE * fp;
fp = fopen(logstatfile, "w+");
if (fp)
{
// General Stats
fprintf(fp,"## GENERAL\nRX:%ld\nTX:%ld\nDROP:%ld\n## PORT STATS\n",(long) pkt_rx, (long) pkt_tx, (long) pkt_drop);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does your use case with influxDB support single line entries? I'd prefer single line entries (eg, CSV, JSON, or similar) so that it's more of a traditional log, but I don't mind leaving this as is if you can't use single line :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I choose this way of logfile because it'S still human readable. For pushing it to influxDB I used a sperate bash Script to convert this into a one line insert every 10s.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put the Bash Script I'm using to pusinh this stats into a influxDB at gist:
https://gist.github.com/solariz/29362abbcf45605ab700df6f6e6be141

It's pretty simple, influx can handle a huge amount of posts per second so we're totally fine with that currently. On the last event the influx run on a raspberry pi at a mean CPU cycle of less then 10% :)

// port based stats
for (int i = 0; i < 65535; i++)
if(pkt_stats[i] > 0)
fprintf(fp,"%d:%ld\n",i, (long) pkt_stats[i]);

// interface stats
fprintf(fp,"## IFACE STATS\n");
for (int i = 0; i < num_ifaces; i++)
fprintf(fp,"%s:%ld\n",iface_list[i], (long) iface_data[i].num_packets);
}
fclose(fp);
logtimer = (int)time(NULL);
}
}
/**
* Given a source interface name and a packet, flood that packet to every other
* interface
Expand All @@ -149,6 +189,7 @@ void flood_packet( u_char *source_iface, const struct pcap_pkthdr *header, const
{
int i;
u_char * sendpacket;
pkt_rx += 1;
sendpacket = malloc(header->len);
// This memcpy is only to let me experiment with modifying the packet.
// Not neccessary if not modifying packet, but easier to leave here.
Expand All @@ -172,20 +213,24 @@ void flood_packet( u_char *source_iface, const struct pcap_pkthdr *header, const
if (dstport == NULL)
return;

if (debug)
printf("The port of that packet is %hu \n", ntohs(*dstport)) ;
if (logstat) {
// some Port Statistics for each port
pkt_stats[ntohs(*dstport)] += 1;
// writing some logfile stats.
writeLogStats();
}

// Check if this packet hits the rate limiter
if (timer_check_packet(srcipaddr, dstport) == SEND_PACKET)
{
if (debug)
printf("Ratelimiter said send packet \n");
printf("SEND Packet port %hu addr %hhu.%hhu.%hhu.%hhu len %d bc %d.%d.%d.%d (RX: %ld TX: %ld DROP: %ld)\n", ntohs(*dstport), *(srcipaddr +0 ) , *(srcipaddr +1 ) , *(srcipaddr +2 ) , *(srcipaddr +3 ), header->len,sendpacket[30],sendpacket[31],sendpacket[32],sendpacket[33], (long) pkt_rx, (long) pkt_tx, (long) pkt_drop);
}
else
{
pkt_drop += 1;
if (debug)
printf("Ratelimiter said drop packet\n");

printf("DROP Packet port %hu addr %hhu.%hhu.%hhu.%hhu len %d\n", ntohs(*dstport), *(srcipaddr +0 ) , *(srcipaddr +1 ) , *(srcipaddr +2 ) , *(srcipaddr +3 ), header->len);
// TODO: increment packet_drop_count on iface data
return;
}
Expand All @@ -205,9 +250,6 @@ void flood_packet( u_char *source_iface, const struct pcap_pkthdr *header, const
//printf("Packet checksum: %x\n", in_cksum((unsigned short *)sendpacket, header->len));
}*/

if (debug)
printf("Packet length %d\n", header->len);

for (i = 0; i < num_ifaces; i++)
{
if (strcmp(iface_list[i], (const char *)source_iface) != 0)
Expand All @@ -220,6 +262,7 @@ void flood_packet( u_char *source_iface, const struct pcap_pkthdr *header, const
iface_data[i].num_packets++;
}
}
pkt_tx += 1;

// we only malloc() this if we're modifying the frame
//if (do_network_rewrite>0) // malloc() moved outisde conditional above
Expand Down Expand Up @@ -269,17 +312,16 @@ pcap_t * init_pcap_int ( const char * interface, char * errbuf)
}

// Compile the filter for this interface
if ( pcap_compile(ret, &fp, filter, 0, 0 ) == -1 ) {
// enabled Optimize for Filter compile to avoid memory exception on big port lists
if ( pcap_compile(ret, &fp, filter, 1, 0 ) == -1 ) {
fprintf(stderr, "Error compiling filter");
return NULL;
}

// Apply the filter
if (pcap_setfilter(ret, &fp) == -1 ) {
if (pcap_setfilter(ret, &fp) != 0 ) {
fprintf(stderr, "Error setting filter");
return NULL;
}

// Only listen to input traffic
if (pcap_setdirection(ret, PCAP_D_IN) == -1) {
fprintf(stderr, "Error setting direction");
Expand Down Expand Up @@ -438,7 +480,6 @@ char * generate_filter_string(char * portlist[], int numports)
// Cut off the last "and ", and put a closing bracket on it, then EOF
*(end-4) = ')';
*(end-3) = '\0';

return ret;
}

Expand All @@ -458,7 +499,8 @@ Usage:\n \
-a : Use all interfaces (ignores any interface files given) \n\
-r : Enable rate limiting per source IP+destination UDP port combination\n \
-t nnn : Set rate limiter to nnn ms. Defaults to 1000ms. Implies -r\n \
-d : Turns on debug (doesn't do much yet\n \
-d : Turns on debug (doesn't do much yet)\n \
-l : Turns on Stat logging (log RX/TX Packets to stat.log)\n \
-h : Shows this help\n \
\n\
Multiple port and interface files can be specified.\n\
Expand Down Expand Up @@ -573,6 +615,11 @@ int main(int argc, char * argv[])
{
debug = 1;
}
// -l, log stats
else if (strcmp("-l", argv[i]) == 0)
{
logstat = 1;
}
// -a, all interfaces
else if (strcmp("-a", argv[i]) == 0)
use_all_interfaces = 1;
Expand Down Expand Up @@ -632,7 +679,7 @@ int main(int argc, char * argv[])
iface_data[i].pcap_int = init_pcap_int(iface_list[i], iface_data[i].pcap_errbuf );
if (iface_data[i].pcap_int == NULL)
{
fprintf(stderr, "Couldn't create a listener for all interfaces. Exiting.\n");
fprintf(stderr, "Couldn't create a listener for all interfaces. Exiting. (%d)\n",i);
return -1;
}
}
Expand Down