masscan-mark-ii/src/out-binary.c

370 lines
11 KiB
C

#include "output.h"
#include "masscan-app.h"
#include "masscan-status.h"
#include "out-record.h"
#include "util-safefunc.h"
#include <assert.h>
/****************************************************************************
****************************************************************************/
static void
binary_out_open(struct Output *out, FILE *fp)
{
char firstrecord[2+'a'];
size_t bytes_written;
UNUSEDPARM(out);
memset(firstrecord, 0, 2+'a');
snprintf(firstrecord, 2+'a', "masscan/1.1\ns:%u\n",
(unsigned)out->when_scan_started);
bytes_written = fwrite(firstrecord, 1, 2+'a', fp);
if (bytes_written != 2+'a') {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
/****************************************************************************
****************************************************************************/
static void
binary_out_close(struct Output *out, FILE *fp)
{
char firstrecord[2+'a'];
size_t bytes_written;
UNUSEDPARM(out);
memset(firstrecord, 0, 2+'a');
snprintf(firstrecord, 2+'a', "masscan/1.1");
bytes_written = fwrite(firstrecord, 1, 2+'a', fp);
if (bytes_written != 2+'a') {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
static void
_put_byte(unsigned char *buf, size_t length, size_t *r_offset, unsigned long long num)
{
size_t offset = *r_offset;
(*r_offset) += 1;
if (*r_offset <= length) {
buf[offset++] = (unsigned char)(num>>0);
}
}
static void
_put_short(unsigned char *buf, size_t length, size_t *r_offset, unsigned long long num)
{
size_t offset = *r_offset;
(*r_offset) += 2;
if (*r_offset <= length) {
buf[offset++] = (unsigned char)(num>>8);
buf[offset++] = (unsigned char)(num>>0);
}
}
static void
_put_integer(unsigned char *buf, size_t length, size_t *r_offset, unsigned long long num)
{
size_t offset = *r_offset;
(*r_offset) += 4;
if (*r_offset <= length) {
buf[offset++] = (unsigned char)(num>>24);
buf[offset++] = (unsigned char)(num>>16);
buf[offset++] = (unsigned char)(num>>8);
buf[offset++] = (unsigned char)(num>>0);
}
}
static void
_put_long(unsigned char *buf, size_t length, size_t *r_offset, unsigned long long num)
{
size_t offset = *r_offset;
(*r_offset) += 8;
if (*r_offset <= length) {
buf[offset++] = (unsigned char)(num>>56);
buf[offset++] = (unsigned char)(num>>48);
buf[offset++] = (unsigned char)(num>>40);
buf[offset++] = (unsigned char)(num>>32);
buf[offset++] = (unsigned char)(num>>24);
buf[offset++] = (unsigned char)(num>>16);
buf[offset++] = (unsigned char)(num>>8);
buf[offset++] = (unsigned char)(num>>0);
}
}
/****************************************************************************
****************************************************************************/
static void
binary_out_status_ipv6(struct Output *out, FILE *fp, time_t timestamp,
int status, ipaddress ip, unsigned ip_proto, unsigned port, unsigned reason, unsigned ttl)
{
unsigned char buf[256+1];
size_t max = sizeof(buf)-1;
size_t offset = 0;
size_t bytes_written;
/* [TYPE] field */
switch (status) {
case PortStatus_Open:
_put_byte(buf, max, &offset, Out_Open6);
break;
case PortStatus_Closed:
_put_byte(buf, max, &offset, Out_Closed6);
break;
case PortStatus_Arp:
_put_byte(buf, max, &offset, Out_Arp6);
break;
default:
return;
}
/* [LENGTH] field
* see assert() below */
_put_byte(buf, max, &offset, 26);
_put_integer(buf, max, &offset, timestamp);
_put_byte(buf, max, &offset, ip_proto);
_put_short(buf, max, &offset, port);
_put_byte(buf, max, &offset, reason);
_put_byte(buf, max, &offset, ttl);
_put_byte(buf, max, &offset, ip.version);
_put_long(buf, max, &offset, ip.ipv6.hi);
_put_long(buf, max, &offset, ip.ipv6.lo);
assert(offset == 2 + 26);
bytes_written = fwrite(buf, 1, offset, fp);
if (bytes_written != offset) {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
/****************************************************************************
****************************************************************************/
static void
binary_out_status(struct Output *out, FILE *fp, time_t timestamp,
int status, ipaddress ip, unsigned ip_proto, unsigned port, unsigned reason, unsigned ttl)
{
unsigned char foo[256];
size_t bytes_written;
/* This function is for IPv6, call a different function for IPv6 */
if (ip.version == 6) {
binary_out_status_ipv6(out, fp, timestamp, status, ip, ip_proto, port, reason, ttl);
return;
}
/* [TYPE] field */
switch (status) {
case PortStatus_Open:
foo[0] = Out_Open2;
break;
case PortStatus_Closed:
foo[0] = Out_Closed2;
break;
case PortStatus_Arp:
foo[0] = Out_Arp2;
break;
default:
return;
}
/* [LENGTH] field */
foo[1] = 13;
/* [TIMESTAMP] field */
foo[2] = (unsigned char)(timestamp>>24);
foo[3] = (unsigned char)(timestamp>>16);
foo[4] = (unsigned char)(timestamp>> 8);
foo[5] = (unsigned char)(timestamp>> 0);
foo[6] = (unsigned char)(ip.ipv4 >>24);
foo[7] = (unsigned char)(ip.ipv4 >>16);
foo[8] = (unsigned char)(ip.ipv4 >> 8);
foo[9] = (unsigned char)(ip.ipv4 >> 0);
foo[10] = (unsigned char)(ip_proto);
foo[11] = (unsigned char)(port>>8);
foo[12] = (unsigned char)(port>>0);
foo[13] = (unsigned char)reason;
foo[14] = (unsigned char)ttl;
bytes_written = fwrite(&foo, 1, 15, fp);
if (bytes_written != 15) {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
/****************************************************************************
****************************************************************************/
static void
binary_out_banner_ipv6(struct Output *out, FILE *fp, time_t timestamp,
ipaddress ip, unsigned ip_proto, unsigned port,
enum ApplicationProtocol proto, unsigned ttl,
const unsigned char *px, unsigned length)
{
unsigned char foo[32768];
unsigned i;
size_t bytes_written;
static const unsigned HeaderLength = 14 + 13;
/* [TYPE] field */
foo[0] = Out_Banner6; /*banner*/
/* [LENGTH] field*/
if (length >= 128 * 128 - HeaderLength)
return;
if (length < 128 - HeaderLength) {
foo[1] = (unsigned char)(length + HeaderLength);
i = 2;
} else {
foo[1] = (unsigned char)((length + HeaderLength)>>7) | 0x80;
foo[2] = (unsigned char)((length + HeaderLength) & 0x7F);
i = 3;
}
/* [TIMESTAMP] field */
foo[i+0] = (unsigned char)(timestamp>>24);
foo[i+1] = (unsigned char)(timestamp>>16);
foo[i+2] = (unsigned char)(timestamp>> 8);
foo[i+3] = (unsigned char)(timestamp>> 0);
foo[i+ 4] = (unsigned char)(ip_proto);
foo[i+ 5] = (unsigned char)(port>>8);
foo[i+ 6] = (unsigned char)(port>>0);
foo[i+ 7] = (unsigned char)(proto>>8);
foo[i+ 8] = (unsigned char)(proto>>0);
foo[i+ 9] = (unsigned char)(ttl);
foo[i+10] = (unsigned char)(ip.version);
foo[i+11] = (unsigned char)(ip.ipv6.hi >> 56ULL);
foo[i+12] = (unsigned char)(ip.ipv6.hi >> 48ULL);
foo[i+13] = (unsigned char)(ip.ipv6.hi >> 40ULL);
foo[i+14] = (unsigned char)(ip.ipv6.hi >> 32ULL);
foo[i+15] = (unsigned char)(ip.ipv6.hi >> 24ULL);
foo[i+16] = (unsigned char)(ip.ipv6.hi >> 16ULL);
foo[i+17] = (unsigned char)(ip.ipv6.hi >> 8ULL);
foo[i+18] = (unsigned char)(ip.ipv6.hi >> 0ULL);
foo[i+19] = (unsigned char)(ip.ipv6.lo >> 56ULL);
foo[i+20] = (unsigned char)(ip.ipv6.lo >> 48ULL);
foo[i+21] = (unsigned char)(ip.ipv6.lo >> 40ULL);
foo[i+22] = (unsigned char)(ip.ipv6.lo >> 32ULL);
foo[i+23] = (unsigned char)(ip.ipv6.lo >> 24ULL);
foo[i+24] = (unsigned char)(ip.ipv6.lo >> 16ULL);
foo[i+25] = (unsigned char)(ip.ipv6.lo >> 8ULL);
foo[i+26] = (unsigned char)(ip.ipv6.lo >> 0ULL);
/* Banner */
memcpy(foo+i+14+13, px, length);
bytes_written = fwrite(&foo, 1, length+i+HeaderLength, fp);
if (bytes_written != length+i+HeaderLength) {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
/****************************************************************************
****************************************************************************/
static void
binary_out_banner(struct Output *out, FILE *fp, time_t timestamp,
ipaddress ip, unsigned ip_proto, unsigned port,
enum ApplicationProtocol proto, unsigned ttl,
const unsigned char *px, unsigned length)
{
unsigned char foo[32768];
unsigned i;
size_t bytes_written;
static const unsigned HeaderLength = 14;
if (ip.version == 6) {
binary_out_banner_ipv6(out, fp, timestamp, ip, ip_proto, port, proto, ttl, px, length);
return;
}
/* [TYPE] field */
foo[0] = Out_Banner9; /*banner*/
/* [LENGTH] field*/
if (length >= 128 * 128 - HeaderLength)
return;
if (length < 128 - HeaderLength) {
foo[1] = (unsigned char)(length + HeaderLength);
i = 2;
} else {
foo[1] = (unsigned char)((length + HeaderLength)>>7) | 0x80;
foo[2] = (unsigned char)((length + HeaderLength) & 0x7F);
i = 3;
}
/* [TIMESTAMP] field */
foo[i+0] = (unsigned char)(timestamp>>24);
foo[i+1] = (unsigned char)(timestamp>>16);
foo[i+2] = (unsigned char)(timestamp>> 8);
foo[i+3] = (unsigned char)(timestamp>> 0);
foo[i+4] = (unsigned char)(ip.ipv4 >> 24);
foo[i+5] = (unsigned char)(ip.ipv4 >> 16);
foo[i+6] = (unsigned char)(ip.ipv4 >> 8);
foo[i+7] = (unsigned char)(ip.ipv4 >> 0);
foo[i+8] = (unsigned char)(ip_proto);
foo[i+ 9] = (unsigned char)(port>>8);
foo[i+10] = (unsigned char)(port>>0);
foo[i+11] = (unsigned char)(proto>>8);
foo[i+12] = (unsigned char)(proto>>0);
foo[i+13] = (unsigned char)(ttl);
/* Banner */
memcpy(foo+i+14, px, length);
bytes_written = fwrite(&foo, 1, length+i+HeaderLength, fp);
if (bytes_written != length+i+HeaderLength) {
perror("output");
exit(1);
}
out->rotate.bytes_written += bytes_written;
}
/****************************************************************************
****************************************************************************/
const struct OutputType binary_output = {
"scan",
0,
binary_out_open,
binary_out_close,
binary_out_status,
binary_out_banner,
};