|
Packit |
9c3e7e |
/*
|
|
Packit |
9c3e7e |
* Copyright (C) 2015 Miroslav Lichvar <mlichvar@redhat.com>
|
|
Packit |
9c3e7e |
*
|
|
Packit |
9c3e7e |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
9c3e7e |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
9c3e7e |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
9c3e7e |
* (at your option) any later version.
|
|
Packit |
9c3e7e |
*
|
|
Packit |
9c3e7e |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
9c3e7e |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
9c3e7e |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
9c3e7e |
* GNU General Public License for more details.
|
|
Packit |
9c3e7e |
*
|
|
Packit |
9c3e7e |
* You should have received a copy of the GNU General Public License
|
|
Packit |
9c3e7e |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
9c3e7e |
*/
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
/* This is a minimal replacement for the clknetsim server to allow fuzz
|
|
Packit |
9c3e7e |
testing. There is no clock control or networking. When the time reaches
|
|
Packit |
9c3e7e |
fuzz_start, a packet read from stdin is forwarded to the fuzz_port port of
|
|
Packit |
9c3e7e |
the client, and the client is terminated. Packets sent by the client from
|
|
Packit |
9c3e7e |
the port are written to stdout. */
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
enum {
|
|
Packit |
9c3e7e |
FUZZ_MODE_DISABLED = 0,
|
|
Packit |
9c3e7e |
FUZZ_MODE_ONESHOT = 1,
|
|
Packit |
9c3e7e |
FUZZ_MODE_BURST = 2,
|
|
Packit |
9c3e7e |
FUZZ_MODE_REPLY = 3,
|
|
Packit |
9c3e7e |
FUZZ_MODE_NONE = 4,
|
|
Packit |
9c3e7e |
};
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
static int fuzz_mode;
|
|
Packit |
9c3e7e |
static int fuzz_port;
|
|
Packit |
9c3e7e |
static double fuzz_start;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
static int fuzz_init(void) {
|
|
Packit |
9c3e7e |
const char *env;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
env = getenv("CLKNETSIM_FUZZ_MODE");
|
|
Packit |
9c3e7e |
if (!env)
|
|
Packit |
9c3e7e |
return 0;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
fuzz_mode = atoi(env);
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (fuzz_mode == FUZZ_MODE_DISABLED)
|
|
Packit |
9c3e7e |
return 0;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (fuzz_mode < FUZZ_MODE_ONESHOT || fuzz_mode > FUZZ_MODE_NONE) {
|
|
Packit |
9c3e7e |
fprintf(stderr, "clknetsim: unknown fuzz mode.\n");
|
|
Packit |
9c3e7e |
exit(1);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
env = getenv("CLKNETSIM_FUZZ_PORT");
|
|
Packit |
9c3e7e |
if (!env) {
|
|
Packit |
9c3e7e |
fprintf(stderr, "clknetsim: CLKNETSIM_FUZZ_PORT variable not set.\n");
|
|
Packit |
9c3e7e |
exit(1);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
fuzz_port = atoi(env);
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
env = getenv("CLKNETSIM_FUZZ_START");
|
|
Packit |
9c3e7e |
fuzz_start = env ? atof(env) : 0.1;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
return 1;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
static int fuzz_read_packet(char *data, int maxlen) {
|
|
Packit |
9c3e7e |
int len;
|
|
Packit |
9c3e7e |
uint16_t slen;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (fuzz_mode > FUZZ_MODE_ONESHOT) {
|
|
Packit |
9c3e7e |
if (fread(&slen, 1, sizeof (slen), stdin) != sizeof (slen))
|
|
Packit |
9c3e7e |
return 0;
|
|
Packit |
9c3e7e |
len = ntohs(slen);
|
|
Packit |
9c3e7e |
if (len > maxlen)
|
|
Packit |
9c3e7e |
len = maxlen;
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
len = maxlen;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
return fread(data, 1, len, stdin);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
static void fuzz_write_packet(const char *data, int len) {
|
|
Packit |
9c3e7e |
uint16_t slen;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (fuzz_mode > FUZZ_MODE_ONESHOT) {
|
|
Packit |
9c3e7e |
slen = htons(len);
|
|
Packit |
9c3e7e |
fwrite(&slen, 1, sizeof (slen), stdout);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
fwrite(data, 1, len, stdout);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
static void fuzz_process_reply(int request_id, const union Request_data *request, union Reply_data *reply, int replylen) {
|
|
Packit |
9c3e7e |
static double network_time = 0.0;
|
|
Packit |
9c3e7e |
static int received = 0;
|
|
Packit |
9c3e7e |
static int sent = 0;
|
|
Packit |
9c3e7e |
static int dst_port = 0;
|
|
Packit |
9c3e7e |
static int packet_len = 0;
|
|
Packit |
9c3e7e |
static char packet[MAX_PACKET_SIZE];
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (reply)
|
|
Packit |
9c3e7e |
memset(reply, 0, replylen);
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
switch (request_id) {
|
|
Packit |
9c3e7e |
case REQ_GETTIME:
|
|
Packit |
9c3e7e |
reply->gettime.real_time = network_time;
|
|
Packit |
9c3e7e |
reply->gettime.monotonic_time = network_time;
|
|
Packit |
9c3e7e |
reply->gettime.network_time = network_time;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_SELECT:
|
|
Packit |
9c3e7e |
if (fuzz_mode == FUZZ_MODE_NONE) {
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_TIMEOUT;
|
|
Packit |
9c3e7e |
return;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (!packet_len && (!received || fuzz_mode != FUZZ_MODE_ONESHOT))
|
|
Packit |
9c3e7e |
packet_len = fuzz_read_packet(packet, sizeof (packet));
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (!packet_len) {
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_TERMINATE;
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
if (fuzz_mode == FUZZ_MODE_REPLY) {
|
|
Packit |
9c3e7e |
if (sent > received) {
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_NORMAL;
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
network_time += request->select.timeout;
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_TIMEOUT;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
if (network_time < fuzz_start && !sent) {
|
|
Packit |
9c3e7e |
network_time += request->select.timeout;
|
|
Packit |
9c3e7e |
if (network_time >= fuzz_start) {
|
|
Packit |
9c3e7e |
network_time = fuzz_start;
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_NORMAL;
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_TIMEOUT;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
} else {
|
|
Packit |
9c3e7e |
reply->select.ret = REPLY_SELECT_NORMAL;
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
reply->select.subnet = 0;
|
|
Packit |
9c3e7e |
reply->select.dst_port = dst_port ? dst_port : fuzz_port;
|
|
Packit |
9c3e7e |
reply->select.time.real_time = network_time;
|
|
Packit |
9c3e7e |
reply->select.time.monotonic_time = network_time;
|
|
Packit |
9c3e7e |
reply->select.time.network_time = network_time;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_SEND:
|
|
Packit |
9c3e7e |
if (request->send.to != 1)
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
if (fuzz_mode == FUZZ_MODE_REPLY) {
|
|
Packit |
9c3e7e |
if (request->send.dst_port != fuzz_port)
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
dst_port = request->send.src_port;
|
|
Packit |
9c3e7e |
} else if (request->send.src_port != fuzz_port)
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
|
|
Packit |
9c3e7e |
fuzz_write_packet(request->send.data, request->send.len);
|
|
Packit |
9c3e7e |
sent++;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_RECV:
|
|
Packit |
9c3e7e |
network_time += 1e-1;
|
|
Packit |
9c3e7e |
reply->recv.subnet = 0;
|
|
Packit |
9c3e7e |
reply->recv.from = 1;
|
|
Packit |
9c3e7e |
reply->recv.src_port = fuzz_port;
|
|
Packit |
9c3e7e |
reply->recv.dst_port = dst_port ? dst_port : fuzz_port;
|
|
Packit |
9c3e7e |
memcpy(reply->recv.data, packet, packet_len);
|
|
Packit |
9c3e7e |
reply->recv.len = packet_len;
|
|
Packit |
9c3e7e |
received++;
|
|
Packit |
9c3e7e |
packet_len = 0;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_SETTIME:
|
|
Packit |
9c3e7e |
network_time = request->settime.time;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_ADJTIME:
|
|
Packit |
9c3e7e |
case REQ_GETREFSAMPLE:
|
|
Packit |
9c3e7e |
case REQ_GETREFOFFSETS:
|
|
Packit |
9c3e7e |
case REQ_DEREGISTER:
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_ADJTIMEX:
|
|
Packit |
9c3e7e |
reply->adjtimex.timex.tick = 10000;
|
|
Packit |
9c3e7e |
break;
|
|
Packit |
9c3e7e |
case REQ_REGISTER:
|
|
Packit |
9c3e7e |
default:
|
|
Packit |
9c3e7e |
assert(0);
|
|
Packit |
9c3e7e |
}
|
|
Packit |
9c3e7e |
}
|