Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / m_uping.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_uping.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program 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 1, or (at your option)
12  * any later version.
13  *
14  * This program 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 this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #include "config.h"
83
84 #if 0
85 /*
86  * No need to include handlers.h here the signatures must match
87  * and we don't need to force a rebuild of all the handlers everytime
88  * we add a new one to the list. --Bleep
89  */
90 #include "handlers.h"
91 #endif /* 0 */
92 #include "client.h"
93 #include "hash.h"
94 #include "ircd.h"
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
97 #include "match.h"
98 #include "msg.h"
99 #include "numeric.h"
100 #include "numnicks.h"
101 #include "s_conf.h"
102 #include "s_user.h"
103 #include "send.h"
104 #include "uping.h"
105
106
107 #include <assert.h>
108 #include <stdlib.h>
109 #include <string.h>
110
111 /*
112  * ms_uping - server message handler
113  *
114  * m_uping  -- by Run
115  *
116  * parv[0] = sender prefix
117  * parv[1] = pinged server
118  * parv[2] = port
119  * parv[3] = hunted server
120  * parv[4] = number of requested pings
121  */
122 int ms_uping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
123 {
124   struct ConfItem *aconf;
125   int port;
126   int count;
127
128   assert(0 != cptr);
129   assert(0 != sptr);
130
131   if (!IsAnOper(sptr)) {
132     send_reply(sptr, ERR_NOPRIVILEGES);
133     return 0;
134   }
135
136   if (parc < 5) {
137     send_reply(sptr, ERR_NEEDMOREPARAMS, "UPING");
138     return 0;
139   }
140
141   if (hunt_server_cmd(sptr, CMD_UPING, cptr, 1, "%s %s %C %s", 3, parc, parv)
142       != HUNTED_ISME)
143     return 0;
144   /*
145    * Determine port: First user supplied, then default : 7007
146    */
147   if (EmptyString(parv[2]) || (port = atoi(parv[2])) <= 0)
148     port = atoi(UDP_PORT);
149
150   if (EmptyString(parv[4]) || (count = atoi(parv[4])) <= 0)
151   {
152     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING : Illegal number of "
153                   "packets: %s", sptr, parv[4]);
154     return 0;
155   }
156   /* 
157    * Check if a CONNECT would be possible at all (adapted from m_connect)
158    */
159   if ((aconf = conf_find_server(parv[1])))
160     uping_server(sptr, aconf, port, count);
161   else
162     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host %s not listed in "
163                   "ircd.conf", sptr, parv[1]);
164
165   return 0;
166 }
167
168 /*
169  * mo_uping - oper message handler
170  *
171  * m_uping  -- by Run
172  *
173  * parv[0] = sender prefix
174  * parv[1] = pinged server
175  * parv[2] = port
176  * parv[3] = hunted server
177  * parv[4] = number of requested pings
178  */
179 int mo_uping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
180 {
181   struct ConfItem *aconf;
182   int port;
183   int count;
184
185   assert(0 != cptr);
186   assert(0 != sptr);
187   assert(cptr == sptr);
188
189   assert(IsAnOper(sptr));
190
191   if (parc < 2) {
192     send_reply(sptr, ERR_NEEDMOREPARAMS, "UPING");
193     return 0;
194   }
195
196   if (parc == 2) {
197     parv[parc++] = UDP_PORT;
198     parv[parc++] = cli_name(&me);
199     parv[parc++] = "5";
200   }
201   else if (parc == 3) {
202     if (IsDigit(*parv[2]))
203       parv[parc++] = cli_name(&me);
204     else {
205       parv[parc++] = parv[2];
206       parv[2] = UDP_PORT;
207     }
208     parv[parc++] = "5";
209   }
210   else if (parc == 4) {
211     if (IsDigit(*parv[2])) {
212       if (IsDigit(*parv[3])) {
213         parv[parc++] = parv[3];
214         parv[3] = cli_name(&me);
215       }
216       else
217         parv[parc++] = "5";
218     }
219     else {
220       parv[parc++] = parv[3];
221       parv[3] = parv[2];
222       parv[2] = UDP_PORT;
223     }
224   }
225   if (hunt_server_cmd(sptr, CMD_UPING, sptr, 1, "%s %s %C %s", 3, parc, parv)
226       != HUNTED_ISME)
227     return 0;
228   /*
229    * Determine port: First user supplied, then default : 7007
230    */
231   if (EmptyString(parv[2]) || (port = atoi(parv[2])) <= 0)
232     port = atoi(UDP_PORT);
233
234   if (EmptyString(parv[4]) || (count = atoi(parv[4])) <= 0)
235   {
236     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Illegal number of "
237                   "packets: %s", sptr, parv[4]);
238     return 0;
239   }
240   /* 
241    * Check if a CONNECT would be possible at all (adapted from m_connect)
242    */
243   if ((aconf = conf_find_server(parv[1])))
244     uping_server(sptr, aconf, port, count);
245   else {
246     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host %s not listed in "
247                   "ircd.conf", sptr, parv[1]);
248   }
249   return 0;
250 }
251
252
253 #if 0
254 /*
255  * m_uping  -- by Run
256  *
257  * parv[0] = sender prefix
258  * parv[1] = pinged server
259  * parv[2] = port
260  * parv[3] = hunted server
261  * parv[4] = number of requested pings
262  */
263 int m_uping(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
264 {
265   struct ConfItem *aconf;
266   int port;
267   int fd;
268   struct UPing* pptr = 0;
269
270   if (!IsPrivileged(sptr))
271   {
272     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); /* XXX DEAD */
273     return -1;
274   }
275
276   if (parc < 2)
277   {
278     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UPING"); /* XXX DEAD */
279     return 0;
280   }
281
282   if (MyUser(sptr))
283   {
284     if (parc == 2)
285     {
286       parv[parc++] = UDP_PORT;
287       parv[parc++] = me.name;
288       parv[parc++] = "5";
289     }
290     else if (parc == 3)
291     {
292       if (IsDigit(*parv[2]))
293         parv[parc++] = me.name;
294       else
295       {
296         parv[parc++] = parv[2];
297         parv[2] = UDP_PORT;
298       }
299       parv[parc++] = "5";
300     }
301     else if (parc == 4)
302     {
303       if (IsDigit(*parv[2]))
304       {
305         if (IsDigit(*parv[3]))
306         {
307           parv[parc++] = parv[3];
308           parv[3] = me.name;
309         }
310         else
311           parv[parc++] = "5";
312       }
313       else
314       {
315         parv[parc++] = parv[3];
316         parv[3] = parv[2];
317         parv[2] = UDP_PORT;
318       }
319     }
320   }
321   if (hunt_server(1, cptr, sptr, ":%s UPING %s %s %s %s", 3, parc, parv) != HUNTED_ISME) /* XXX DEAD */
322     return 0;
323
324   if (BadPtr(parv[4]) || atoi(parv[4]) <= 0)
325   {
326     if (MyUser(sptr) || Protocol(cptr) < 10)
327       sendto_one(sptr, ":%s NOTICE %s :UPING: Illegal number of packets: %s", /* XXX DEAD */
328           me.name, parv[0], parv[4]);
329     else
330       sendto_one(sptr, "%s NOTICE %s%s :UPING: Illegal number of packets: %s", /* XXX DEAD */
331           NumServ(&me), NumNick(sptr), parv[4]);
332     return 0;
333   }
334
335   /* Check if a CONNECT would be possible at all (adapted from m_connect) */
336   for (aconf = GlobalConfList; aconf; aconf = aconf->next)
337   {
338     if (aconf->status == CONF_SERVER &&
339         match(parv[1], aconf->name) == 0)
340       break;
341   }
342   if (!aconf)
343   {
344     for (aconf = GlobalConfList; aconf; aconf = aconf->next)
345     {
346       if (aconf->status == CONF_SERVER &&
347           (match(parv[1], aconf->host) == 0 ||
348            match(parv[1], strchr(aconf->host, '@') + 1) == 0))
349         break;
350     }
351   }
352   if (!aconf)
353   {
354     if (MyUser(sptr) || Protocol(cptr) < 10)
355       sendto_one(sptr, ":%s NOTICE %s :UPING: Host %s not listed in ircd.conf", /* XXX DEAD */
356           me.name, parv[0], parv[1]);
357     else
358       sendto_one(sptr, /* XXX DEAD */
359           "%s NOTICE %s%s :UPING: Host %s not listed in ircd.conf",
360           NumServ(&me), NumNick(sptr), parv[1]);
361     return 0;
362   }
363
364   if (IsUPing(sptr))
365     cancel_ping(sptr, sptr);  /* Cancel previous ping request */
366
367   /*
368    * Determine port: First user supplied, then default : 7007
369    */
370   if (BadPtr(parv[2]) || (port = atoi(parv[2])) <= 0)
371     port = atoi(UDP_PORT);
372
373   if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
374     int err = errno;
375     sendto_ops("m_uping: socket: %s", (err != EMFILE)  /* XXX DEAD */
376                 ? ((strerror(err)) ? strerror(err) : "Unknown error") : "No more sockets");
377     if (MyUser(sptr) || Protocol(cptr) < 10)
378       sendto_one(sptr,  /* XXX DEAD */
379                  ":%s NOTICE %s :UPING: Unable to create udp ping socket",
380                  me.name, parv[0]);
381     else
382       sendto_one(sptr, /* XXX DEAD */
383                  "%s NOTICE %s%s :UPING: Unable to create udp ping socket",
384                  NumServ(&me), NumNick(sptr));
385     ircd_log(L_ERROR, "UPING: Unable to create UDP socket"); /* XXX DEAD */
386     return 0;
387   }
388
389   if (!os_set_nonblocking(fd)) {
390     if (MyUser(sptr) || Protocol(cptr) < 10)
391       sendto_one(sptr, ":%s NOTICE %s :UPING: Can't set fd non-blocking", /* XXX DEAD */
392             me.name, parv[0]);
393     else
394       sendto_one(sptr, "%s NOTICE %s%s :UPING: Can't set fd non-blocking", /* XXX DEAD */
395             NumServ(&me), NumNick(sptr));
396     close(fd);
397     return 0;
398   }
399   pptr = (struct UPing*) MyMalloc(sizeof(struct UPing));
400   assert(0 != pptr);
401   memset(pptr, 0, sizeof(struct UPing));
402
403   pptr->fd = fd;
404   pptr->sin.sin_port = htons(port);
405   pptr->sin.sin_addr.s_addr = aconf->ipnum.s_addr;
406   pptr->sin.sin_family = AF_INET;
407   pptr->count = IRCD_MIN(20, atoi(parv[4]));
408   strcpy(pptr->name, aconf->host);
409   pptr->client = sptr;
410   pptr->index = -1;
411
412   pptr->next = pingList;
413   pingList = pptr;
414
415   SetUPing(sptr);
416   ping_server(pptr);
417   return 0;
418 }
419 #endif /* 0 */
420