Postfix3.3.1
anvil_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* anvil_clnt 3
4 /* SUMMARY
5 /* connection count and rate management client interface
6 /* SYNOPSIS
7 /* #include <anvil_clnt.h>
8 /*
9 /* ANVIL_CLNT *anvil_clnt_create(void)
10 /*
11 /* void anvil_clnt_free(anvil_clnt)
12 /* ANVIL_CLNT *anvil_clnt;
13 /*
14 /* int anvil_clnt_connect(anvil_clnt, service, addr,
15 /* count, rate)
16 /* ANVIL_CLNT *anvil_clnt;
17 /* const char *service;
18 /* const char *addr;
19 /* int *count;
20 /* int *rate;
21 /*
22 /* int anvil_clnt_mail(anvil_clnt, service, addr, msgs)
23 /* ANVIL_CLNT *anvil_clnt;
24 /* const char *service;
25 /* const char *addr;
26 /* int *msgs;
27 /*
28 /* int anvil_clnt_rcpt(anvil_clnt, service, addr, rcpts)
29 /* ANVIL_CLNT *anvil_clnt;
30 /* const char *service;
31 /* const char *addr;
32 /* int *rcpts;
33 /*
34 /* int anvil_clnt_newtls(anvil_clnt, service, addr, newtls)
35 /* ANVIL_CLNT *anvil_clnt;
36 /* const char *service;
37 /* const char *addr;
38 /* int *newtls;
39 /*
40 /* int anvil_clnt_newtls_stat(anvil_clnt, service, addr, newtls)
41 /* ANVIL_CLNT *anvil_clnt;
42 /* const char *service;
43 /* const char *addr;
44 /* int *newtls;
45 /*
46 /* int anvil_clnt_auth(anvil_clnt, service, addr, auths)
47 /* ANVIL_CLNT *anvil_clnt;
48 /* const char *service;
49 /* const char *addr;
50 /* int *auths;
51 /*
52 /* int anvil_clnt_disconnect(anvil_clnt, service, addr)
53 /* ANVIL_CLNT *anvil_clnt;
54 /* const char *service;
55 /* const char *addr;
56 /*
57 /* int anvil_clnt_lookup(anvil_clnt, service, addr, count,
58 /* rate, msgs, rcpts, ntls, auths)
59 /* ANVIL_CLNT *anvil_clnt;
60 /* const char *service;
61 /* const char *addr;
62 /* int *count;
63 /* int *rate;
64 /* int *msgs;
65 /* int *rcpts;
66 /* int *ntls;
67 /* int *auths;
68 /* DESCRIPTION
69 /* anvil_clnt_create() instantiates a local anvil service
70 /* client endpoint.
71 /*
72 /* anvil_clnt_connect() informs the anvil server that a
73 /* remote client has connected, and returns the current
74 /* connection count and connection rate for that remote client.
75 /*
76 /* anvil_clnt_mail() registers a MAIL FROM event and
77 /* returns the current MAIL FROM rate for the specified remote
78 /* client.
79 /*
80 /* anvil_clnt_rcpt() registers a RCPT TO event and
81 /* returns the current RCPT TO rate for the specified remote
82 /* client.
83 /*
84 /* anvil_clnt_newtls() registers a remote client request
85 /* to negotiate a new (uncached) TLS session and returns the
86 /* current newtls request rate for the specified remote client.
87 /*
88 /* anvil_clnt_newtls_stat() returns the current newtls request
89 /* rate for the specified remote client.
90 /*
91 /* anvil_clnt_auth() registers an AUTH event and returns the
92 /* current AUTH event rate for the specified remote client.
93 /*
94 /* anvil_clnt_disconnect() informs the anvil server that a remote
95 /* client has disconnected.
96 /*
97 /* anvil_clnt_lookup() returns the current count and rate
98 /* information for the specified client.
99 /*
100 /* anvil_clnt_free() destroys a local anvil service client
101 /* endpoint.
102 /*
103 /* Arguments:
104 /* .IP anvil_clnt
105 /* Client rate control service handle.
106 /* .IP service
107 /* The service that the remote client is connected to.
108 /* .IP addr
109 /* Null terminated string that identifies the remote client.
110 /* .IP count
111 /* Pointer to storage for the current number of connections from
112 /* this remote client.
113 /* .IP rate
114 /* Pointer to storage for the current connection rate for this
115 /* remote client.
116 /* .IP msgs
117 /* Pointer to storage for the current message rate for this
118 /* remote client.
119 /* .IP rcpts
120 /* Pointer to storage for the current recipient rate for this
121 /* remote client.
122 /* .IP newtls
123 /* Pointer to storage for the current "new TLS session" rate
124 /* for this remote client.
125 /* .IP auths
126 /* Pointer to storage for the current AUTH event rate for this
127 /* remote client.
128 /* DIAGNOSTICS
129 /* The update and status query routines return
130 /* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise
131 /* (either the communication with the server is broken or the
132 /* server experienced a problem).
133 /* SEE ALSO
134 /* anvil(8), connection/rate limiting
135 /* LICENSE
136 /* .ad
137 /* .fi
138 /* The Secure Mailer license must be distributed with this software.
139 /* AUTHOR(S)
140 /* Wietse Venema
141 /* IBM T.J. Watson Research
142 /* P.O. Box 704
143 /* Yorktown Heights, NY 10598, USA
144 /*
145 /* Wietse Venema
146 /* Google, Inc.
147 /* 111 8th Avenue
148 /* New York, NY 10011, USA
149 /*--*/
150 
151 /* System library. */
152 
153 #include <sys_defs.h>
154 
155 /* Utility library. */
156 
157 #include <mymalloc.h>
158 #include <msg.h>
159 #include <attr_clnt.h>
160 #include <stringops.h>
161 
162 /* Global library. */
163 
164 #include <mail_proto.h>
165 #include <mail_params.h>
166 #include <anvil_clnt.h>
167 
168 /* Application specific. */
169 
170 #define ANVIL_IDENT(service, addr) \
171  printable(concatenate(service, ":", addr, (char *) 0), '?')
172 
173 /* anvil_clnt_create - instantiate connection rate service client */
174 
176 {
178 
179  /*
180  * Use whatever IPC is preferred for internal use: UNIX-domain sockets or
181  * Solaris streams.
182  */
183 #ifndef VAR_ANVIL_SERVICE
184  anvil_clnt = attr_clnt_create("local:" ANVIL_CLASS "/" ANVIL_SERVICE,
185  var_ipc_timeout, 0, 0);
186 #else
187  anvil_clnt = attr_clnt_create(var_anvil_service, var_ipc_timeout, 0, 0);
188 #endif
189  return ((ANVIL_CLNT *) anvil_clnt);
190 }
191 
192 /* anvil_clnt_free - destroy connection rate service client */
193 
195 {
196  attr_clnt_free((ATTR_CLNT *) anvil_clnt);
197 }
198 
199 /* anvil_clnt_lookup - status query */
200 
201 int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
202  const char *addr, int *count, int *rate,
203  int *msgs, int *rcpts, int *newtls, int *auths)
204 {
205  char *ident = ANVIL_IDENT(service, addr);
206  int status;
207 
208  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
209  ATTR_FLAG_NONE, /* Query attributes. */
213  ATTR_FLAG_MISSING, /* Reply attributes. */
221  ATTR_TYPE_END) != 7)
222  status = ANVIL_STAT_FAIL;
223  else if (status != ANVIL_STAT_OK)
224  status = ANVIL_STAT_FAIL;
225  myfree(ident);
226  return (status);
227 }
228 
229 /* anvil_clnt_connect - heads-up and status query */
230 
231 int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service,
232  const char *addr, int *count, int *rate)
233 {
234  char *ident = ANVIL_IDENT(service, addr);
235  int status;
236 
237  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
238  ATTR_FLAG_NONE, /* Query attributes. */
242  ATTR_FLAG_MISSING, /* Reply attributes. */
246  ATTR_TYPE_END) != 3)
247  status = ANVIL_STAT_FAIL;
248  else if (status != ANVIL_STAT_OK)
249  status = ANVIL_STAT_FAIL;
250  myfree(ident);
251  return (status);
252 }
253 
254 /* anvil_clnt_mail - heads-up and status query */
255 
256 int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service,
257  const char *addr, int *msgs)
258 {
259  char *ident = ANVIL_IDENT(service, addr);
260  int status;
261 
262  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
263  ATTR_FLAG_NONE, /* Query attributes. */
267  ATTR_FLAG_MISSING, /* Reply attributes. */
270  ATTR_TYPE_END) != 2)
271  status = ANVIL_STAT_FAIL;
272  else if (status != ANVIL_STAT_OK)
273  status = ANVIL_STAT_FAIL;
274  myfree(ident);
275  return (status);
276 }
277 
278 /* anvil_clnt_rcpt - heads-up and status query */
279 
280 int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service,
281  const char *addr, int *rcpts)
282 {
283  char *ident = ANVIL_IDENT(service, addr);
284  int status;
285 
286  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
287  ATTR_FLAG_NONE, /* Query attributes. */
291  ATTR_FLAG_MISSING, /* Reply attributes. */
294  ATTR_TYPE_END) != 2)
295  status = ANVIL_STAT_FAIL;
296  else if (status != ANVIL_STAT_OK)
297  status = ANVIL_STAT_FAIL;
298  myfree(ident);
299  return (status);
300 }
301 
302 /* anvil_clnt_newtls - heads-up and status query */
303 
304 int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service,
305  const char *addr, int *newtls)
306 {
307  char *ident = ANVIL_IDENT(service, addr);
308  int status;
309 
310  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
311  ATTR_FLAG_NONE, /* Query attributes. */
315  ATTR_FLAG_MISSING, /* Reply attributes. */
318  ATTR_TYPE_END) != 2)
319  status = ANVIL_STAT_FAIL;
320  else if (status != ANVIL_STAT_OK)
321  status = ANVIL_STAT_FAIL;
322  myfree(ident);
323  return (status);
324 }
325 
326 /* anvil_clnt_newtls_stat - status query */
327 
328 int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service,
329  const char *addr, int *newtls)
330 {
331  char *ident = ANVIL_IDENT(service, addr);
332  int status;
333 
334  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
335  ATTR_FLAG_NONE, /* Query attributes. */
339  ATTR_FLAG_MISSING, /* Reply attributes. */
342  ATTR_TYPE_END) != 2)
343  status = ANVIL_STAT_FAIL;
344  else if (status != ANVIL_STAT_OK)
345  status = ANVIL_STAT_FAIL;
346  myfree(ident);
347  return (status);
348 }
349 
350 /* anvil_clnt_auth - heads-up and status query */
351 
352 int anvil_clnt_auth(ANVIL_CLNT *anvil_clnt, const char *service,
353  const char *addr, int *auths)
354 {
355  char *ident = ANVIL_IDENT(service, addr);
356  int status;
357 
358  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
359  ATTR_FLAG_NONE, /* Query attributes. */
363  ATTR_FLAG_MISSING, /* Reply attributes. */
366  ATTR_TYPE_END) != 2)
367  status = ANVIL_STAT_FAIL;
368  else if (status != ANVIL_STAT_OK)
369  status = ANVIL_STAT_FAIL;
370  myfree(ident);
371  return (status);
372 }
373 
374 /* anvil_clnt_disconnect - heads-up only */
375 
376 int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service,
377  const char *addr)
378 {
379  char *ident = ANVIL_IDENT(service, addr);
380  int status;
381 
382  if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
383  ATTR_FLAG_NONE, /* Query attributes. */
387  ATTR_FLAG_MISSING, /* Reply attributes. */
389  ATTR_TYPE_END) != 1)
390  status = ANVIL_STAT_FAIL;
391  else if (status != ANVIL_STAT_OK)
392  status = ANVIL_STAT_FAIL;
393  myfree(ident);
394  return (status);
395 }
396 
397 #ifdef TEST
398 
399  /*
400  * Stand-alone client for testing.
401  */
402 #include <unistd.h>
403 #include <string.h>
404 #include <msg_vstream.h>
405 #include <mail_conf.h>
406 #include <mail_params.h>
407 #include <vstring_vstream.h>
408 
409 static void usage(void)
410 {
411  vstream_printf("usage: "
412  ANVIL_REQ_CONN " service addr | "
413  ANVIL_REQ_DISC " service addr | "
414  ANVIL_REQ_MAIL " service addr | "
415  ANVIL_REQ_RCPT " service addr | "
416  ANVIL_REQ_NTLS " service addr | "
417  ANVIL_REQ_NTLS_STAT " service addr | "
418  ANVIL_REQ_AUTH " service addr | "
419  ANVIL_REQ_LOOKUP " service addr\n");
420 }
421 
422 int main(int unused_argc, char **argv)
423 {
424  VSTRING *inbuf = vstring_alloc(1);
425  char *bufp;
426  char *cmd;
427  ssize_t cmd_len;
428  char *service;
429  char *addr;
430  int count;
431  int rate;
432  int msgs;
433  int rcpts;
434  int newtls;
435  int auths;
436  ANVIL_CLNT *anvil;
437 
438  msg_vstream_init(argv[0], VSTREAM_ERR);
439 
440  mail_conf_read();
441  msg_info("using config files in %s", var_config_dir);
442  if (chdir(var_queue_dir) < 0)
443  msg_fatal("chdir %s: %m", var_queue_dir);
444 
445  msg_verbose++;
446 
447  anvil = anvil_clnt_create();
448 
449  while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
450  bufp = vstring_str(inbuf);
451  if ((cmd = mystrtok(&bufp, " ")) == 0 || *bufp == 0
452  || (service = mystrtok(&bufp, " ")) == 0 || *service == 0
453  || (addr = mystrtok(&bufp, " ")) == 0 || *addr == 0
454  || mystrtok(&bufp, " ") != 0) {
455  vstream_printf("bad command syntax\n");
456  usage();
458  continue;
459  }
460  cmd_len = strlen(cmd);
461  if (strncmp(cmd, ANVIL_REQ_CONN, cmd_len) == 0) {
462  if (anvil_clnt_connect(anvil, service, addr, &count, &rate) != ANVIL_STAT_OK)
463  msg_warn("error!");
464  else
465  vstream_printf("count=%d, rate=%d\n", count, rate);
466  } else if (strncmp(cmd, ANVIL_REQ_MAIL, cmd_len) == 0) {
467  if (anvil_clnt_mail(anvil, service, addr, &msgs) != ANVIL_STAT_OK)
468  msg_warn("error!");
469  else
470  vstream_printf("rate=%d\n", msgs);
471  } else if (strncmp(cmd, ANVIL_REQ_RCPT, cmd_len) == 0) {
472  if (anvil_clnt_rcpt(anvil, service, addr, &rcpts) != ANVIL_STAT_OK)
473  msg_warn("error!");
474  else
475  vstream_printf("rate=%d\n", rcpts);
476  } else if (strncmp(cmd, ANVIL_REQ_NTLS, cmd_len) == 0) {
477  if (anvil_clnt_newtls(anvil, service, addr, &newtls) != ANVIL_STAT_OK)
478  msg_warn("error!");
479  else
480  vstream_printf("rate=%d\n", newtls);
481  } else if (strncmp(cmd, ANVIL_REQ_AUTH, cmd_len) == 0) {
482  if (anvil_clnt_auth(anvil, service, addr, &auths) != ANVIL_STAT_OK)
483  msg_warn("error!");
484  else
485  vstream_printf("rate=%d\n", auths);
486  } else if (strncmp(cmd, ANVIL_REQ_NTLS_STAT, cmd_len) == 0) {
487  if (anvil_clnt_newtls_stat(anvil, service, addr, &newtls) != ANVIL_STAT_OK)
488  msg_warn("error!");
489  else
490  vstream_printf("rate=%d\n", newtls);
491  } else if (strncmp(cmd, ANVIL_REQ_DISC, cmd_len) == 0) {
492  if (anvil_clnt_disconnect(anvil, service, addr) != ANVIL_STAT_OK)
493  msg_warn("error!");
494  else
495  vstream_printf("OK\n");
496  } else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) {
497  if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, &msgs,
498  &rcpts, &newtls, &auths) != ANVIL_STAT_OK)
499  msg_warn("error!");
500  else
501  vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d "
502  "auths=%d\n", count, rate, msgs, rcpts, newtls,
503  auths);
504  } else {
505  vstream_printf("bad command: \"%s\"\n", cmd);
506  usage();
507  }
509  }
510  vstring_free(inbuf);
511  anvil_clnt_free(anvil);
512  return (0);
513 }
514 
515 #endif
int msg_verbose
Definition: msg.c:177
#define vstring_fgets_nonl(s, p)
int var_ipc_timeout
Definition: mail_params.c:255
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
void attr_clnt_free(ATTR_CLNT *client)
Definition: attr_clnt.c:122
#define ANVIL_CLASS
Definition: anvil_clnt.h:28
int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *rcpts)
Definition: anvil_clnt.c:280
#define ANVIL_REQ_MAIL
Definition: anvil_clnt.h:33
#define vstring_str(vp)
Definition: vstring.h:71
#define ANVIL_ATTR_REQ
Definition: anvil_clnt.h:30
#define VSTREAM_OUT
Definition: vstream.h:67
#define ATTR_FLAG_MISSING
Definition: attr.h:99
int main(int argc, char **argv)
Definition: anvil.c:1010
#define ANVIL_IDENT(service, addr)
Definition: anvil_clnt.c:170
int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *count, int *rate, int *msgs, int *rcpts, int *newtls, int *auths)
Definition: anvil_clnt.c:201
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *newtls)
Definition: anvil_clnt.c:328
#define ANVIL_ATTR_MAIL
Definition: anvil_clnt.h:42
char * var_config_dir
Definition: mail_params.c:241
int anvil_clnt_auth(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *auths)
Definition: anvil_clnt.c:352
#define VSTREAM_IN
Definition: vstream.h:66
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
void anvil_clnt_free(ANVIL_CLNT *anvil_clnt)
Definition: anvil_clnt.c:194
#define ANVIL_ATTR_RATE
Definition: anvil_clnt.h:41
int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *count, int *rate)
Definition: anvil_clnt.c:231
ATTR_CLNT * attr_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
Definition: attr_clnt.c:130
void mail_conf_read(void)
Definition: mail_conf.c:178
int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr)
Definition: anvil_clnt.c:376
#define ANVIL_REQ_LOOKUP
Definition: anvil_clnt.h:38
#define ANVIL_ATTR_COUNT
Definition: anvil_clnt.h:40
#define ANVIL_SERVICE
Definition: anvil_clnt.h:27
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define ANVIL_REQ_DISC
Definition: anvil_clnt.h:32
ANVIL_CLNT * anvil_clnt
Definition: smtpd.c:1461
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define ANVIL_REQ_AUTH
Definition: anvil_clnt.h:37
#define ANVIL_STAT_OK
Definition: anvil_clnt.h:48
#define ANVIL_ATTR_AUTH
Definition: anvil_clnt.h:45
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define ANVIL_ATTR_STATUS
Definition: anvil_clnt.h:46
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
struct ANVIL_CLNT ANVIL_CLNT
Definition: anvil_clnt.h:54
int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *newtls)
Definition: anvil_clnt.c:304
#define ANVIL_ATTR_IDENT
Definition: anvil_clnt.h:39
int attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
Definition: attr_clnt.c:148
int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *msgs)
Definition: anvil_clnt.c:256
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define ANVIL_ATTR_NTLS
Definition: anvil_clnt.h:44
char * var_queue_dir
Definition: mail_params.c:246
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define ANVIL_STAT_FAIL
Definition: anvil_clnt.h:49
#define ANVIL_REQ_RCPT
Definition: anvil_clnt.h:34
#define ANVIL_REQ_NTLS_STAT
Definition: anvil_clnt.h:36
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define ANVIL_REQ_CONN
Definition: anvil_clnt.h:31
ANVIL_CLNT * anvil_clnt_create(void)
Definition: anvil_clnt.c:175
#define VSTREAM_ERR
Definition: vstream.h:68
#define ANVIL_ATTR_RCPT
Definition: anvil_clnt.h:43
#define ANVIL_REQ_NTLS
Definition: anvil_clnt.h:35
void msg_info(const char *fmt,...)
Definition: msg.c:199