masscan-mark-ii/src/proto-ntp.c

300 lines
8.0 KiB
C

/*
NTP protocol handler
*/
#include "proto-ntp.h"
#include <stdint.h>
#include <stdlib.h>
#include "smack.h"
#include "util-safefunc.h"
#include "output.h"
#include "masscan-app.h"
#include "proto-preprocess.h"
#include "proto-banner1.h"
#include "syn-cookie.h"
#include "massip-port.h"
#include "unusedparm.h"
/****************************************************************************
****************************************************************************/
unsigned
ntp_set_cookie(unsigned char *px, size_t length, uint64_t seqno)
{
UNUSEDPARM(px);
UNUSEDPARM(length);
UNUSEDPARM(seqno);
return 0;
}
struct Val2String {
unsigned value;
const char *string;
};
static const struct Val2String request_codes[] = {
{ 0, "PEER_LIST" },
{ 1, "PEER_LIST_SUM" },
{ 2, "PEER_INFO" },
{ 3, "PEER_STATS" },
{ 4, "SYS_INFO" },
{ 5, "SYS_STATS" },
{ 6, "IO_STATS" },
{ 7, "MEM_STATS" },
{ 8, "LOOP_INFO" },
{ 9, "TIMER_STATS" },
{ 10, "CONFIG" },
{ 11, "UNCONFIG" },
{ 12, "SET_SYS_FLAG" },
{ 13, "CLR_SYS_FLAG" },
{ 16, "GET_RESTRICT" },
{ 17, "RESADDFLAGS" },
{ 18, "RESSUBFLAGS" },
{ 19, "UNRESTRICT" },
{ 20, "MON_GETLIST" },
{ 21, "RESET_STATS" },
{ 22, "RESET_PEER" },
{ 23, "REREAD_KEYS" },
{ 26, "TRUSTKEY" },
{ 27, "UNTRUSTKEY" },
{ 28, "AUTHINFO" },
{ 29, "TRAPS" },
{ 30, "ADD_TRAP" },
{ 31, "CLR_TRAP" },
{ 32, "REQUEST_KEY" },
{ 33, "CONTROL_KEY" },
{ 34, "GET_CTLSTATS" },
{ 36, "GET_CLOCKINFO" },
{ 37, "SET_CLKFUDGE" },
{ 38, "GET_KERNEL" },
{ 39, "GET_CLKBUGINFO" },
{ 42, "MON_GETLIST_1" },
{ 43, "HOSTNAME_ASSOCID" },
{ 0, 0}
};
struct Val2String error_codes[] = {
{0, "No Error"},
{1, "Incompatible Implementation Number"},
{2, "Unimplemented Request Code"},
{3, "Format Error"},
{4, "No Data Available"},
{7, "Authentication Failure"},
{0,0}
};
/*****************************************************************************
*****************************************************************************/
static const char *
val2string_lookup(const struct Val2String *list, unsigned val)
{
unsigned i;
for (i=0; list[i].string; i++) {
if (list[i].value == val)
return list[i].string;
}
return 0;
}
/*****************************************************************************
*****************************************************************************/
static void
ntp_modlist_parse(const unsigned char *px,
unsigned length,
struct BannerOutput *banout,
unsigned *request_id)
{
unsigned offset = 4;
unsigned errcode;
unsigned record_count;
unsigned record_size;
UNUSEDPARM(request_id);
if (offset + 4 >= length)
return;
errcode = (px[offset]>>4)&0xF;
record_count = (px[offset+0]&0xF) << 8 | px[offset+1];
record_size = (px[offset+2]&0xF) << 8 | px[offset+3];
if (errcode) {
char foo[12];
const char *errmsg = val2string_lookup(error_codes, errcode);
if (errmsg == 0)
errmsg = "Bogus Error Code";
snprintf(foo, sizeof(foo), "%u", errcode);
banout_append(banout, PROTO_NTP, "Response was NTP Error Code ", AUTO_LEN);
banout_append(banout, PROTO_NTP, foo, AUTO_LEN);
banout_append(banout, PROTO_NTP, " - \"", AUTO_LEN);
banout_append(banout, PROTO_NTP, errmsg, AUTO_LEN);
banout_append(banout, PROTO_NTP, "\"", AUTO_LEN);
return;
}
if (4 + record_count * record_size > length) {
banout_append(banout, PROTO_NTP, "response-too-big", AUTO_LEN);
return;
}
if (record_count * record_size > 500) {
banout_append(banout, PROTO_NTP, "response-too-big", AUTO_LEN);
return;
}
//offset += 4;
{
char msg[128];
snprintf(msg, sizeof(msg), " response-size=%u-bytes more=%s",
record_count * record_size, ((px[0]>>6)&1)?"true":"false");
banout_append(banout, PROTO_NTP, msg, AUTO_LEN);
}
}
/*****************************************************************************
*****************************************************************************/
static void
ntp_priv(const unsigned char *px,
unsigned length,
struct BannerOutput *banout,
unsigned *request_id)
{
unsigned implementation = px[2];
unsigned request_code = px[3];
const char *request_string;
switch (implementation) {
case 0: banout_append(banout, PROTO_NTP, "UNIV", 4); return;
case 2: banout_append(banout, PROTO_NTP, "XNTPD-OLD", 9); return;
case 3: banout_append(banout, PROTO_NTP, "XNTPD", 5); break;
default:
return;
}
request_string = val2string_lookup(request_codes, request_code);
if (request_string) {
banout_append(banout, PROTO_NTP, " ", 1);
banout_append(banout, PROTO_NTP, request_string, strlen(request_string));
}
switch (request_code) {
case 42:
ntp_modlist_parse(px, length, banout, request_id);
break;
}
}
/*****************************************************************************
*****************************************************************************/
static void
ntp_v2_parse(const unsigned char *px,
unsigned length,
struct BannerOutput *banout,
unsigned *request_id)
{
unsigned mode;
if (length < 4)
return;
/* Validate: response bit is set */
if ((px[0]>>7) != 1)
return;
/* Validate: this is version 2 */
if (((px[0]>>3)&7) != 2)
return;
/* Extract: mode */
mode = px[0] & 7;
switch (mode) {
case 6: /* control */
break;
case 7:
ntp_priv(px, length, banout, request_id);
break;
}
}
/*****************************************************************************
* Handles an NTP response.
*****************************************************************************/
unsigned
ntp_handle_response(struct Output *out, time_t timestamp,
const unsigned char *px, unsigned length,
struct PreprocessedInfo *parsed,
uint64_t entropy
)
{
ipaddress ip_them = parsed->src_ip;
unsigned request_id = 0;
struct BannerOutput banout[1];
unsigned offset = parsed->app_offset;
UNUSEDPARM(length);
UNUSEDPARM(entropy);
if (parsed->app_length < 4)
return 0;
/* Initialize the "banner output" module that we'll use to print
* pretty text in place of the raw packet */
banout_init(banout);
/* Parse the packet */
switch ((px[offset]>>3)&7) {
case 2:
ntp_v2_parse(
px + parsed->app_offset, /* incoming response */
parsed->app_length, /* length of response */
banout, /* banner printing */
&request_id); /* syn-cookie info */
break;
default:
banout_release(banout);
return 0;
}
/* Validate the "syn-cookie" style information. */
//seqno = (unsigned)syn_cookie(ip_them, port_them | Templ_UDP, ip_me, port_me);
//if ((seqno&0x7FFFffff) != request_id)
// return 1;
/* Print the banner information, or save to a file, depending */
output_report_banner(
out, timestamp,
ip_them, 17, parsed->port_src,
PROTO_NTP,
parsed->ip_ttl,
banout_string(banout, PROTO_NTP),
banout_string_length(banout, PROTO_NTP));
/* Free memory for the banner, if there was any allocated */
banout_release(banout);
return 0;
}
/****************************************************************************
****************************************************************************/
int
ntp_selftest(void)
{
return 0;
}