1 /*
2  * ----------------------------------------------------------------
3  * ircproxy - Connection SendQ Functions
4  * ----------------------------------------------------------------
5  * Copyright (C) 1997-2009 Jonas Kvinge
6  *
7  * This file is part of ircproxy.
8  *
9  * ircproxy is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * ircproxy is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with ircproxy.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * Additional permission under GNU GPL version 3 section 7
23  *
24  * If you modify ircproxy, or any covered work, by linking or
25  * combining it with openssl (or a modified version of that library),
26  * containing parts covered by the terms of the OpenSSL License and the
27  * SSLeay License, the licensors of ircproxy grant you additional
28  * permission to convey the resulting work.
29  *
30  * $Id: conn_sendq.c 54 2009-03-18 18:23:29Z jonasio $
31  *
32  */
33 
34 #define CONN_SENDQ_C
35 
36 #define NEED_SYS_TYPES_H 1		/* Extra types */
37 #define NEED_SYS_PARAM_H 1		/* Some systems need this */
38 #define NEED_LIMITS_H 0			/* Kernel limits */
39 #define NEED_STDARG_H 1			/* va_list, etc */
40 #define NEED_ERRNO_H 1			/* errno */
41 #define NEED_CTYPE_H 1			/* isdigit(), etc */
42 #define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
43 #define NEED_ARPA_INET_H 0		/* inet_ntoa(), inet_aton(), etc */
44 #define NEED_STDIO_H 1			/* Standard C UNIX functions */
45 #define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
46 #define NEED_TIME_H 1			/* time(), etc */
47 #define NEED_SYSCTL_H 0			/* sysctl(), etc */
48 #define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
49 #define NEED_SYS_UIO_H 0		/* iovec, etc */
50 #define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
51 #define NEED_SYS_IOCTL_H 0		/* ioctl(), etc */
52 #define NEED_SYS_FILIO_H 0		/* Solaris need this for ioctl(), etc */
53 #define NEED_UNISTD_H 1			/* Unix standard functions */
54 #define NEED_STRING_H 1			/* C string functions */
55 #define NEED_SIGNAL_H 0			/* Signal functions */
56 #define NEED_SYS_SOCKET_H 0		/* Socket functions */
57 #define NEED_NETDB_H 0			/* Network database functions */
58 #define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
59 #define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */
60 #define NEED_ARES 0			/* Functions needed for ares */
61 #define NEED_SSL 1			/* Needed for SSL support */
62 
63 #include "includes.h"
64 #include "irc.h"
65 
66 #include "conf.h"
67 
68 #include "access_conf.h"
69 
70 #include "conn.h"
71 #include "conn_conf.h"
72 #include "conn_connection.h"
73 #include "conn_sendq.h"
74 #include "conn_log.h"
75 
76 #include "client.h"
77 #include "client_connection.h"
78 #include "client_notice.h"
79 
80 /* VARIABLES - JONAS (31.07.2001) */
81 
82 extern struct Conf_Struct ConfS;
83 extern struct Client_Struct *Client_Head;
84 
85 /* CONN_ADDSENDQ FUNCTION - JONAS (01.07.2000) */
86 
conn_addsendq(struct Conn_Struct * ConnS,const char * const LinePT,...)87 void conn_addsendq(struct Conn_Struct *ConnS, const char *const LinePT, ...) {
88 
89   char Line[IRC_MSGLEN+1] = "";
90   va_list Args;
91   struct SendQ_Struct *SendQ = NULL;
92   struct SendQ_Struct *SendQ_NEW = NULL;
93   struct SendQ_Struct *SendQ_PRV = NULL;
94   struct Client_Struct *ClientS = NULL;
95 
96   assert(ConnS != NULL);
97   assert(LinePT != NULL);
98 
99   va_start(Args, LinePT);
100   vsnprintf(Line, IRC_MSGLEN+1, LinePT, Args);
101   va_end(Args);
102 
103   if (!Conn_IsSocket(ConnS)) {
104     sysprint(BITMASK_ERROR, "conn_addsendq() called for connection %s without socket: %s.", ConnS->Name, Line);
105     return;
106   }
107 
108   if (ConnConf_IsRawLog(ConnS)) {
109     if (strncasecmp(Line, "PASS ", 5) == FALSE) { conn_rawlog(ConnS, "---> PASS <HIDDEN>"); }
110     else if (strncasecmp(Line, "OPER ", 5) == FALSE) { conn_rawlog(ConnS, "---> OPER <HIDDEN>"); }
111     else { conn_rawlog(ConnS, "---> %s", Line); }
112   }
113 
114 #if DEBUG && (BITMASK_DEBUG_OPTIONS & BITMASK_DEBUG_CONN_SENDQ)
115   client_noticealluser(ConnS->User, "Connection %s: Adding line \"%s\" to sendQ.", ConnS->Name, Line);
116   client_noticealluser(ConnS->User, "Connection %s: Allowed buffer to be sent: %ld - Allowed number of lines to be sent: %ld.", ConnS->Name, ConnS->SendQMaxFlushBuffer, ConnS->SendQMaxFlushLines);
117 #endif
118 
119   SendQ_NEW = malloc(sizeof(struct SendQ_Struct));
120   if (SendQ_NEW == NULL) { return; }
121 
122   memset(SendQ_NEW, 0, sizeof(struct SendQ_Struct));
123 
124   SendQ_NEW->Line = strdup(Line);
125   if (SendQ_NEW->Line == NULL) {
126     free(SendQ_NEW);
127     return;
128   }
129 
130   SendQ_NEW->Time = NOW;
131 
132   if (strncasecmp(Line, "PASS ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
133   else if (strncasecmp(Line, "NICK ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
134   else if (strncasecmp(Line, "USER ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
135   else if (strncasecmp(Line, "PONG ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
136   else if (strncasecmp(Line, "QUIT ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
137 
138   else if (strncasecmp(Line, "JOIN ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
139   else if (strncasecmp(Line, "PART ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
140   else if (strncasecmp(Line, "ISON ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
141   else if (strncasecmp(Line, "MODE ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
142   else if (strncasecmp(Line, "OPER ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
143   else if (strncasecmp(Line, "KILL ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
144   else if (strncasecmp(Line, "NAMES ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
145   else if (strncasecmp(Line, "LINKS ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
146   else if (strncasecmp(Line, "WHO ", 4) == FALSE) { SendQ_NEW->Priority = 2; }
147   else if (strncasecmp(Line, "WHOIS ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
148   else if (strncasecmp(Line, "AWAY ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
149   else if (strncasecmp(Line, "PING ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
150   else if (strncasecmp(Line, "USERHOST ", 9) == FALSE) { SendQ_NEW->Priority = 2; }
151 
152   else if (strncasecmp(Line, "KICK ", 5) == FALSE) { SendQ_NEW->Priority = 3; }
153 
154   else if (strncasecmp(Line, "PRIVMSG ", 8) == FALSE) { SendQ_NEW->Priority = 4; }
155   else if (strncasecmp(Line, "NOTICE ", 7) == FALSE) { SendQ_NEW->Priority = 4; }
156   else if (strncasecmp(Line, "INVITE ", 7) == FALSE) { SendQ_NEW->Priority = 4; }
157   else if (strncasecmp(Line, "TOPIC ", 6) == FALSE) { SendQ_NEW->Priority = 4; }
158 
159   else { SendQ_NEW->Priority = 4; }
160 
161   if (ConnS->SendQ_Head == NULL) { ConnS->SendQ_Head = SendQ_NEW; }
162   else {
163     for (SendQ = ConnS->SendQ_Head ; SendQ != NULL ;) {
164       if (SendQ->Priority > SendQ_NEW->Priority) {
165         if (SendQ_PRV == NULL) {
166           ConnS->SendQ_Head = SendQ_NEW;
167           SendQ_NEW->Next = SendQ;
168         }
169         else {
170           SendQ_PRV->Next = SendQ_NEW;
171           SendQ_NEW->Next = SendQ;
172         }
173         break;
174       }
175       SendQ_PRV = SendQ;
176       SendQ = SendQ->Next;
177     }
178     if (SendQ == NULL) { SendQ_PRV->Next = SendQ_NEW; }
179   }
180 
181   ++ConnS->NumSendQs;
182 
183   if (ConnS->NumSendQs >= ConfS.ClientMaxSendQ) {
184 #if 0
185     conn_quit(ConnS, ACCESS_CONF_SENDQFLOOD);
186 #endif
187     for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) {
188       if (!Client_IsVerified(ClientS)) { continue; }
189       if (ClientS->ConnS != ConnS) { continue; }
190       client_close(ClientS, ACCESS_CONF_SENDQFLOOD);
191       access_conf_adddeny(ClientS->HostName, ACCESS_CONF_SENDQFLOOD);
192     }
193   }
194 
195 }
196 
197 /* CONN_FLUSHSENDQ FUNCTION - JONAS (24.06.2001) */
198 
conn_flushsendq(struct Conn_Struct * ConnS)199 void conn_flushsendq(struct Conn_Struct *ConnS) {
200 
201   struct SendQ_Struct *SendQ = NULL;
202   struct FlushL_Struct *FlushL = NULL;
203   struct FlushB_Struct *FlushB = NULL;
204   unsigned long int Duration = 0;
205   unsigned short int Count = 0;
206   unsigned short int Len = 0;
207   unsigned short int FlushLen = 0;
208 
209   assert(ConnS != NULL);
210   assert(ConnS->SendQ_Head != NULL);
211 
212   while (ConnS->FlushL_Head != NULL) {
213     FlushL = ConnS->FlushL_Head;
214     Duration = (NOW - FlushL->Time);
215     if (Duration < ConnS->SendLineTime) { break; }
216     ConnS->SendQMaxFlushLines += FlushL->Lines;
217 
218     ConnS->FlushL_Head = FlushL->Next;
219     if (FlushL->Next == NULL) { ConnS->FlushL_Tail = NULL; }
220     else { FlushL->Next->Prev = NULL; }
221 
222     free(FlushL);
223     ConnS->NumFlushLs--;
224   }
225 
226   while (ConnS->FlushB_Head != NULL) {
227     FlushB = ConnS->FlushB_Head;
228     Duration = (NOW - FlushB->Time);
229     if (Duration < ConnS->SendBufferTime) { break; }
230     ConnS->SendQMaxFlushBuffer += FlushB->Len;
231 
232     ConnS->FlushB_Head = FlushB->Next;
233     if (FlushB->Next == NULL) { ConnS->FlushB_Tail = NULL; }
234     else { FlushB->Next->Prev = NULL; }
235 
236     free(FlushB);
237     ConnS->NumFlushBs--;
238   }
239 
240   while ((ConnS->SendQ_Head != NULL) && (ConnS->SendQMaxFlushLines > 0) && (ConnS->SendQMaxFlushBuffer > 0)) {
241     SendQ = ConnS->SendQ_Head;
242     Len = strlen(SendQ->Line) + 2;
243     if (Len > ConnS->SendQMaxFlushBuffer) { break; }
244     ConnS->NumSendQs--;
245     ConnS->SendQ_Head = ConnS->SendQ_Head->Next;
246     conn_addsend(ConnS, SendQ->Line);
247     ConnS->SendQMaxFlushLines--;
248     ConnS->SendQMaxFlushBuffer -= Len;
249     FlushLen += Len;
250     free(SendQ->Line);
251     free(SendQ);
252     Count++;
253   }
254 
255   if (Count > 0) {
256     conn_addflushl(ConnS, Count);
257     conn_addflushb(ConnS, FlushLen);
258   }
259 
260 }
261 
262 /* CONN_INITSENDQ FUNCTION - JONAS (01.07.2000) */
263 
conn_initsendq(struct Conn_Struct * ConnS)264 void conn_initsendq(struct Conn_Struct *ConnS) {
265 
266   struct SendQ_Struct *SendQ = NULL;
267 
268   assert(ConnS != NULL);
269 
270   conn_initflushl(ConnS);
271   conn_initflushb(ConnS);
272 
273   while (ConnS->SendQ_Head != NULL) {
274     SendQ = ConnS->SendQ_Head;
275     ConnS->SendQ_Head = ConnS->SendQ_Head->Next;
276     free(SendQ->Line);
277     free(SendQ);
278     ConnS->NumSendQs--;
279   }
280   assert(ConnS->NumSendQs == 0);
281 
282   ConnS->SendQMaxFlushLines = ConnS->SendMaxLines;
283   ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer;
284 
285 }
286 
287 /* CONN_ADDFLUSHL FUNCTION - JONAS (24.06.2001) */
288 
conn_addflushl(struct Conn_Struct * ConnS,const unsigned short int Lines)289 void conn_addflushl(struct Conn_Struct *ConnS, const unsigned short int Lines) {
290 
291   struct FlushL_Struct *FlushL = NULL;
292   struct FlushL_Struct *FlushL_NEW = NULL;
293 
294   assert(ConnS != NULL);
295 
296   FlushL_NEW = malloc(sizeof(struct FlushL_Struct));
297   if (FlushL_NEW == NULL) { return; }
298 
299   memset(FlushL_NEW, 0, sizeof(struct FlushL_Struct));
300 
301   FlushL_NEW->Lines = Lines;
302   FlushL_NEW->Time = NOW;
303 
304   if (ConnS->FlushL_Head == NULL) {
305     ConnS->FlushL_Head = FlushL_NEW;
306     ConnS->FlushL_Tail = FlushL_NEW;
307   }
308   else {
309     FlushL = ConnS->FlushL_Tail;
310     FlushL->Next = FlushL_NEW;
311     FlushL_NEW->Prev = FlushL;
312     ConnS->FlushL_Tail = FlushL_NEW;
313   }
314 
315   ConnS->NumFlushLs++;
316 
317 }
318 
319 /* CONN_INITFLUSHL FUNCTION - JONAS (24.06.2001) */
320 
conn_initflushl(struct Conn_Struct * ConnS)321 void conn_initflushl(struct Conn_Struct *ConnS) {
322 
323   struct FlushL_Struct *FlushL = NULL;
324 
325   assert(ConnS != NULL);
326 
327   while (ConnS->FlushL_Head != NULL) {
328     FlushL = ConnS->FlushL_Head;
329     ConnS->FlushL_Head = ConnS->FlushL_Head->Next;
330     free(FlushL);
331     ConnS->NumFlushLs--;
332   }
333   ConnS->FlushL_Tail = NULL;
334   assert(ConnS->NumFlushLs == 0);
335 
336   ConnS->SendQMaxFlushLines = ConnS->SendMaxLines;
337 
338 }
339 
340 /* CONN_ADDFLUSHB FUNCTION - JONAS (24.06.2001) */
341 
conn_addflushb(struct Conn_Struct * ConnS,const unsigned short int Len)342 void conn_addflushb(struct Conn_Struct *ConnS, const unsigned short int Len) {
343 
344   struct FlushB_Struct *FlushB = NULL;
345   struct FlushB_Struct *FlushB_NEW = NULL;
346 
347   assert(ConnS != NULL);
348 
349   FlushB_NEW = malloc(sizeof(struct FlushB_Struct));
350   if (FlushB_NEW == NULL) { return; }
351 
352   memset(FlushB_NEW, 0, sizeof(struct FlushB_Struct));
353 
354   FlushB_NEW->Len = Len;
355   FlushB_NEW->Time = NOW;
356 
357   if (ConnS->FlushB_Head == NULL) {
358     ConnS->FlushB_Head = FlushB_NEW;
359     ConnS->FlushB_Tail = FlushB_NEW;
360   }
361   else {
362     FlushB = ConnS->FlushB_Tail;
363     FlushB->Next = FlushB_NEW;
364     FlushB_NEW->Prev = FlushB;
365     ConnS->FlushB_Tail = FlushB_NEW;
366   }
367 
368   ConnS->NumFlushBs++;
369 
370 }
371 
372 /* CONN_INITFLUSHB FUNCTION - JONAS (24.06.2001) */
373 
conn_initflushb(struct Conn_Struct * ConnS)374 void conn_initflushb(struct Conn_Struct *ConnS) {
375 
376   struct FlushB_Struct *FlushB = NULL;
377 
378   assert(ConnS != NULL);
379 
380   while (ConnS->FlushB_Head != NULL) {
381     FlushB = ConnS->FlushB_Head;
382     ConnS->FlushB_Head = ConnS->FlushB_Head->Next;
383     free(FlushB);
384     ConnS->NumFlushBs--;
385   }
386   ConnS->FlushB_Tail = NULL;
387   assert(ConnS->NumFlushBs == 0);
388 
389   ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer;
390 
391 }
392