-
Notifications
You must be signed in to change notification settings - Fork 3
/
dnsproxy.h
736 lines (596 loc) · 16.9 KB
/
dnsproxy.h
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
// dnsproxy.h
// DNS Proxy Filter Server
// Copyright (c) 2010-2019 Untangle, Inc.
// All Rights Reserved
// Written by Michael A. Hotz
#ifndef VERSION
#define VERSION "TEST"
#endif
#ifndef BUILDID
#define BUILDID "0"
#endif
const int SOCKBUFFER = 0x10000; // sets the size of the socet recv buffer
const int DNSBUFFER = 0x4000; // sets the size of the dns packet buffer
const int STARTWAIT = 50000; // microsecond wait time for thread startup
const int SOCKLIMIT = 1024; // sets maximum number of listen sockets
const int POOLMAX = 1024; // maximum number of threads in a pool
const int BLACKLIST = 'B';
const int WHITELIST = 'W';
const int FALSE = 0;
const int TRUE = 1;
const int MSG_ADDQUERYTHREAD = 0x11111111;
const int MSG_ADDREPLYTHREAD = 0x22222222;
/*--------------------------------------------------------------------------*/
struct netportal
{
struct sockaddr_in addr;
int ifidx;
int proto;
int sock;
int length;
struct netportal *next,*last;
time_t created;
};
/*--------------------------------------------------------------------------*/
struct category_info
{
int id;
char *name;
char *description;
};
/*--------------------------------------------------------------------------*/
union dnsflags
{
unsigned short value;
struct
{
unsigned short status : 4;
unsigned short reserved : 3;
unsigned short haverec : 1;
unsigned short wantrec : 1;
unsigned short truncate : 1;
unsigned short authority : 1;
unsigned short opcode : 4;
unsigned short response : 1;
} pf;
};
/*--------------------------------------------------------------------------*/
struct header
{
unsigned short qid;
union dnsflags flags;
unsigned short qdcount;
unsigned short ancount;
unsigned short nscount;
unsigned short arcount;
};
/*--------------------------------------------------------------------------*/
struct qrec
{
char qname[260];
unsigned short qtype;
unsigned short qclass;
};
/*--------------------------------------------------------------------------*/
class arec
{
};
/*--------------------------------------------------------------------------*/
class CountDevice;
class SyncDevice;
class AtomicValue;
class ClientNetwork;
class MessageFrame;
class ThreadLogic;
class ServerNetwork;
class ProxyTable;
class ProxyEntry;
class ProxyMessage;
class MessageQueue;
class ThreadPool;
class ThreadItem;
class QueryFilter;
class ReplyFilter;
class LoggerInfo;
class Logger;
class Database;
class FilterManager;
class DNSPacket;
class HashTable;
class HashObject;
class NetworkEntry;
/*--------------------------------------------------------------------------*/
class CountDevice
{
public:
inline CountDevice(void) { sem_init(&control,0,0); }
inline ~CountDevice(void) { sem_destroy(&control); }
inline int operator++(int) { return(sem_post(&control)); }
inline int operator--(int) { return(sem_wait(&control)); }
inline operator int()
{
int value;
sem_getvalue(&control,&value);
return(value);
}
private:
sem_t control;
};
/*--------------------------------------------------------------------------*/
class SyncDevice
{
public:
inline SyncDevice(void) { pthread_mutex_init(&control,NULL); }
inline ~SyncDevice(void) { pthread_mutex_destroy(&control); }
inline void Acquire(void) { pthread_mutex_lock(&control); }
inline void Release(void) { pthread_mutex_unlock(&control); }
private:
pthread_mutex_t control;
};
/*--------------------------------------------------------------------------*/
class AtomicValue
{
public:
inline AtomicValue(unsigned long long aValue = 0) { value = aValue; }
inline ~AtomicValue(void) { }
inline unsigned long long val(void)
{
control.Acquire();
unsigned long long temp = value;
control.Release();
return(temp);
}
inline unsigned long long operator=(const unsigned long long aValue)
{
control.Acquire();
value = aValue;
control.Release();
return(aValue);
}
inline unsigned long long operator++(int)
{
control.Acquire();
unsigned long long temp = ++value;
control.Release();
return(temp);
}
inline unsigned long long operator++()
{
control.Acquire();
unsigned long long temp = value++;
control.Release();
return(temp);
}
inline unsigned long long operator--(int)
{
control.Acquire();
unsigned long long temp = --value;
control.Release();
return(temp);
}
inline unsigned long long operator--()
{
control.Acquire();
unsigned long long temp = value--;
control.Release();
return(temp);
}
inline operator unsigned long long()
{
control.Acquire();
unsigned long long temp = value;
control.Release();
return(temp);
}
private:
unsigned long long value;
SyncDevice control;
};
/*--------------------------------------------------------------------------*/
class ThreadLogic
{
public:
ThreadLogic(void);
virtual ~ThreadLogic(void);
void BeginExecution(int argWait = 0);
void ScramExecution(void);
private:
static void* ThreadMaster(void *aObject);
virtual void* ThreadWorker(void) = 0;
protected:
pthread_t ThreadHandle;
sem_t ThreadSignal;
int ThreadNumber;
};
/*--------------------------------------------------------------------------*/
class MessageFrame
{
friend class MessageQueue;
public:
MessageFrame(int argCmd = 0) { next = NULL; cmd = argCmd; }
virtual ~MessageFrame(void) { }
int cmd;
private:
MessageFrame *next;
};
/*--------------------------------------------------------------------------*/
class ClientNetwork : public ThreadLogic
{
public:
ClientNetwork(void);
~ClientNetwork(void);
int CheckStatus(void) { return(running); }
int ForwardTCPReply(ProxyEntry *argEntry);
int ForwardUDPReply(ProxyEntry *argEntry);
private:
void* ThreadWorker(void);
void RemoveSession(struct netportal *argPortal);
void EnumerateInterfaces(void);
void SocketDestroy(void);
int ProcessTCPConnect(netportal *argPortal);
int ProcessTCPQuery(netportal *argPortal);
int ProcessUDPQuery(netportal *argPortal);
int SessionCleanup(int argForce = 0);
int SocketStartup(void);
unsigned int IPv4list[SOCKLIMIT];
int IPv4tot;
char netbuffer[SOCKBUFFER];
char netface[SOCKLIMIT][32];
netportal tcplisten[SOCKLIMIT];
netportal udplisten[SOCKLIMIT];
netportal *tcpactive;
int tcpcount;
int pollsock;
int running;
};
/*--------------------------------------------------------------------------*/
class ServerNetwork : public ThreadLogic
{
public:
ServerNetwork(void);
~ServerNetwork(void);
int CheckStatus(void) { return(running); }
int ForwardTCPQuery(ProxyEntry *argEntry);
int ForwardUDPQuery(ProxyEntry *argEntry);
private:
void* ThreadWorker(void);
void RemoveSession(struct netportal *argPortal);
void SocketDestroy(void);
int ProcessUDPReply(netportal *argPortal);
int ProcessTCPReply(netportal *argPortal);
int SessionCleanup(int argForce = 0);
int SocketStartup(void);
char netbuffer[SOCKBUFFER];
netportal udpsocket[SOCKLIMIT];
netportal *tcpactive;
int tcpcount;
int pollsock;
int running;
};
/*--------------------------------------------------------------------------*/
class ProxyTable
{
public:
ProxyTable(int argSize);
~ProxyTable(void);
int InsertObject(ProxyEntry *argEntry);
int RemoveObject(unsigned short argGrid,unsigned short argSlot);
ProxyEntry *RetrieveObject(unsigned short argGrid,unsigned short argSlot);
private:
ProxyEntry ***worktable;
unsigned short tablesize;
unsigned short slotindex;
unsigned short gridindex;
};
/*--------------------------------------------------------------------------*/
class ProxyEntry
{
public:
ProxyEntry(void);
~ProxyEntry(void);
int InsertQuery(const char *argBuffer,int argSize,netportal *argPortal);
int InsertReply(const char *argBuffer,int argSize);
int InsertReply(DNSPacket *argPacket);
struct sockaddr_in origin;
unsigned short mygrid;
unsigned short myslot;
int netprotocol;
int netsocket;
char *rawquery;
int rawqsize;
char *rawreply;
int rawrsize;
header q_header;
qrec q_record;
};
/*--------------------------------------------------------------------------*/
class ProxyMessage : public MessageFrame
{
friend class MessageQueue;
public:
ProxyMessage(unsigned short argGrid,unsigned short argSlot) { qgrid = argGrid; qslot = argSlot; }
virtual ~ProxyMessage(void) { }
unsigned short qgrid;
unsigned short qslot;
};
/*--------------------------------------------------------------------------*/
class MessageQueue
{
public:
MessageQueue(void);
virtual ~MessageQueue(void);
void PushMessage(MessageFrame *argObject);
MessageFrame *GrabMessage(void);
sem_t MessageSignal;
private:
SyncDevice *ListLock;
MessageFrame *ListHead;
MessageFrame *ListTail;
};
/*--------------------------------------------------------------------------*/
class ThreadPool : public MessageQueue
{
public:
ThreadPool(int aCount,int aLimit,const char *argName);
virtual ~ThreadPool(void);
void BeginExecution(int argWait = 0);
void InsertThread(int argStart = 0);
void RemoveThread(void);
void EnterCallback(void);
void LeaveCallback(void);
virtual void ThreadCallback(MessageFrame *argMessage) = 0;
virtual void ThreadSaturation(int argTotal) { }
char *PoolName;
int ThreadLimit;
private:
AtomicValue ThreadCounter;
CountDevice BusyCounter;
ThreadItem *ThreadList;
int ThreadTotal;
};
/*--------------------------------------------------------------------------*/
class ThreadItem : public ThreadLogic
{
friend class ThreadPool;
public:
ThreadItem(ThreadPool *argParent,int argIndex);
~ThreadItem(void);
private:
void* ThreadWorker(void);
ThreadPool *Parent;
ThreadItem *last;
ThreadItem *next;
int ThreadNumber;
};
/*--------------------------------------------------------------------------*/
class QueryFilter : public ThreadPool
{
public:
QueryFilter(int aCount,int aLimit);
~QueryFilter(void);
private:
void ThreadCallback(MessageFrame *argMessage);
void ThreadSaturation(int argTotal);
void TransmitBlockTarget(ProxyEntry *argEntry);
Database *database;
};
/*--------------------------------------------------------------------------*/
class ReplyFilter : public ThreadPool
{
public:
ReplyFilter(int aCount,int aLimit);
~ReplyFilter(void);
private:
void ThreadCallback(MessageFrame *argMessage);
void ThreadSaturation(int argTotal);
};
/*--------------------------------------------------------------------------*/
class LoggerInfo : public MessageFrame
{
friend class ThreadPool;
friend class Logger;
public:
LoggerInfo(int aLevel,int aSize = 1024);
~LoggerInfo(void);
void Resize(int aSize);
private:
int level;
int bsize;
const char *prefix;
char *detail;
};
/*--------------------------------------------------------------------------*/
class Logger : public MessageQueue, public ThreadLogic
{
public:
Logger(const char *aProgram,const char *aTitle,int aConsole);
~Logger(void);
void LogMessage(int level,const char *format,...);
void LogBuffer(int level,int size,const char *prefix,const char *buffer);
void LogBinary(int level,const char *info,const void *data,int length);
private:
void* ThreadWorker(void);
void WriteMessage(LoggerInfo *aMess);
char *VALUEtoLEVEL(int value,char *dest);
timeval runtime;
char *ourprogram;
char *ourtitle;
int terminate;
int console;
};
/*--------------------------------------------------------------------------*/
class FilterManager : public MessageQueue, public ThreadLogic
{
public:
FilterManager(void);
~FilterManager(void);
private:
void* ThreadWorker(void);
};
/*--------------------------------------------------------------------------*/
class Database
{
public:
Database(void);
~Database(void);
HashTable *BuildNetworkTable(void);
unsigned long ResultToValue(void);
int CheckPolicyList(int list,NetworkEntry *network,const char *qname);
private:
void HandleError(const char *function,const char *file,int line);
MYSQL context;
char querybuff[10240];
int error_flag;
};
/*--------------------------------------------------------------------------*/
class DNSPacket
{
friend class ProxyEntry;
public:
DNSPacket(void);
~DNSPacket(void);
void Insert_Master(unsigned short aId,unsigned short aFlags,short qd,short an,short ns,short ar);
void Update_Master(unsigned short aId,unsigned short aFlags,short qd,short an,short ns,short ar);
void Insert_Question(const char *aName,int aType,int aClass);
void Begin_Record(const char *aName,short aType,short aClass,long aLife);
void Close_Record(void);
void Insert_DNAME(const char *aData);
void Insert_IPV4(const char *aData);
void Insert_IPV6(const char *aData);
void Insert_INT8(const char *aData);
void Insert_INT8(char aValue);
void Insert_INT16(const char *aData);
void Insert_INT16(short aValue);
void Insert_INT32(const char *aData);
void Insert_INT32(long aValue);
void Insert_STRING(const char *aData);
void Insert_BINARY(const void *aData,int aSize);
int Extract_DNAME(char *target,unsigned tlen);
int Extract_IPV4(char *target,unsigned tlen);
int Extract_INT8(char *target,unsigned tlen);
int Extract_INT16(char *target,unsigned tlen);
int Extract_INT32(char *target,unsigned tlen);
int Extract_STRING(char *target,unsigned tlen);
int Search_DNAME(const char *jungle,const char *needle);
private:
unsigned short *marker;
unsigned short offset;
char *buffer;
int length;
int prefix;
// TODO - do we really need all this stuff
unsigned short id;
unsigned short flags;
unsigned short qdcount;
unsigned short ancount;
unsigned short nscount;
unsigned short arcount;
unsigned short *idval;
unsigned short *flval;
unsigned short *qdval;
unsigned short *anval;
unsigned short *nsval;
unsigned short *arval;
int complist[1024];
int comptot;
};
/*--------------------------------------------------------------------------*/
class HashTable
{
public:
HashTable(int argBuckets);
~HashTable(void);
int InsertObject(HashObject *argObject);
HashObject* SearchObject(const char *argString);
void GetTableSize(int &aCount,int &aBytes);
private:
unsigned int HashKey(const char *argString);
pthread_mutex_t *control;
HashObject **table;
int buckets;
};
/*--------------------------------------------------------------------------*/
class HashObject
{
friend class HashTable;
public:
HashObject(const char *argTitle);
virtual ~HashObject(void);
virtual int GetObjectSize(void);
private:
HashObject *next;
char *ObjectName;
};
/*--------------------------------------------------------------------------*/
class NetworkEntry : public HashObject
{
public:
NetworkEntry(unsigned long aObject,unsigned long aOwner,const char* aNetwork);
virtual ~NetworkEntry(void);
unsigned long Object;
unsigned long Owner;
private:
int GetObjectSize(void);
};
/*--------------------------------------------------------------------------*/
void process_message(const MessageFrame *message);
void load_configuration(void);
void sighandler(int sigval);
char *strclean(char *s);
char *newstr(const char *s);
void freestr(char *s);
/*--------------------------------------------------------------------------*/
#ifndef DATALOC
#define DATALOC extern
#endif
/*--------------------------------------------------------------------------*/
DATALOC struct itimerval g_itimer;
DATALOC pthread_key_t g_threadkey;
DATALOC category_info *g_catinfo;
DATALOC FilterManager *g_manager;
DATALOC MessageQueue *g_master;
DATALOC ClientNetwork *g_client;
DATALOC ServerNetwork *g_server;
DATALOC QueryFilter *g_qfilter;
DATALOC ReplyFilter *g_rfilter;
DATALOC ProxyTable *g_table;
DATALOC HashTable *g_network;
DATALOC Database *g_database;
DATALOC Logger *g_log;
DATALOC void *g_catbuff;
DATALOC size_t g_catcount;
DATALOC int g_console;
DATALOC int g_goodbye;
DATALOC int g_debug;
DATALOC AtomicValue g_clientcount;
DATALOC AtomicValue g_servercount;
DATALOC AtomicValue g_querycount;
DATALOC AtomicValue g_replycount;
DATALOC AtomicValue g_dirtycount;
/*--------------------------------------------------------------------------*/
DATALOC unsigned int cfg_NetFilterAddr[256];
DATALOC unsigned int cfg_NetFilterMask[256];
DATALOC char cfg_LogFiles[1024];
DATALOC int cfg_LogClientBinary;
DATALOC int cfg_LogServerBinary;
DATALOC int cfg_LogDatabase;
DATALOC int cfg_NetFilterCount;
DATALOC int cfg_ListenBacklog;
DATALOC int cfg_SessionTimeout;
DATALOC int cfg_SessionLimit;
DATALOC int cfg_ServerPort;
DATALOC char cfg_BlockServerAddr[32];
DATALOC char cfg_PushServerAddr[32];
DATALOC char cfg_PushLocalAddr[32];
DATALOC int cfg_PushServerPort;
DATALOC int cfg_PushLocalPort;
DATALOC int cfg_PushLocalCount;
DATALOC int cfg_QueryThreads,cfg_QueryLimit;
DATALOC int cfg_ReplyThreads,cfg_ReplyLimit;
DATALOC char cfg_SQLhostname[256];
DATALOC char cfg_SQLusername[256];
DATALOC char cfg_SQLpassword[256];
DATALOC char cfg_SQLdatabase[256];
DATALOC int cfg_SQLflags;
DATALOC int cfg_SQLport;
/*--------------------------------------------------------------------------*/