]> jfr.im git - irc/quakenet/newserv.git/blame - proxyscan/proxyscanmail.c
merge
[irc/quakenet/newserv.git] / proxyscan / proxyscanmail.c
CommitLineData
c86edd1d
Q
1#include "../core/error.h"
2#include "../lib/irc_string.h"
3#include "proxyscan.h"
4#include "../core/events.h"
5
6#include <unistd.h>
7#include <string.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <sys/fcntl.h>
13#include <poll.h>
14#include <errno.h>
15#include <time.h>
16
17#define PSM_NOTCONNECTED 0x00
18#define PSM_CONNECTING 0x01
19#define PSM_SENTHELLO 0x02
20#define PSM_IDLE 0x03
21#define PSM_SENTFROM 0x04
22#define PSM_SENTTO1 0x05
23#define PSM_SENTTO2 0x06
24#define PSM_SENTDATA 0x07
25#define PSM_SENTBODY 0x08
26
27struct psmail {
28 char content[2000];
29 struct psmail *next;
30};
31
32void ps_flushall();
33void ps_mailconnect();
34int ps_flushbuf();
35
36const char *psmailtemplate = "From: QuakeNet Proxyscan <proxyscan@quakenet.org>\r\n"
37 "To: <bopm@reports.blitzed.org>\r\n"
38 "Subject: Open proxy report\r\n\r\n";
39
40const char *psmailfooter = ".\r\n";
41
42struct psmail *mailqueue;
43char psm_sendbuf[3000];
44int psm_sbufsize;
45int psm_mailerfd;
46int psm_state;
47
48void ps_makereportmail(scanhost *shp) {
49 struct psmail *themail;
50 int pos=0;
51 int i;
52 char timebuf[30];
53
54 Error("proxyscan",ERR_INFO,"Generating report mail for %s.",IPtostr(shp->IP));
55
56 themail=(struct psmail *)malloc(sizeof(struct psmail));
57 strcpy(themail->content, psmailtemplate);
58 pos=strlen(psmailtemplate);
59
60 for (i=0;i<PSCAN_MAXSCANS;i++) {
61 if (shp->scans[i] && shp->scans[i]->outcome == SOUTCOME_OPEN) {
62 pos += sprintf(themail->content + pos, "%s: %s:%d\r\n", scantostr(shp->scans[i]->type), IPtostr(shp->IP), shp->scans[i]->port);
63 }
64 }
65
66 strftime(timebuf,30,"%Y-%m-%d %H:%M:%S",gmtime(&(shp->connecttime)));
67 pos += sprintf(themail->content + pos, "\r\n%s: %s connected to %s.\r\n", timebuf, shp->hostmask, shp->servername);
68
69 strcpy(themail->content + pos, psmailfooter);
70
71 if (!mailqueue) {
72 /* There's no mail queue outstanding atm, so let's kick the machinery into action */
73 if (psm_state == PSM_IDLE && psm_mailerfd>-1) {
74 psm_sbufsize = sprintf(psm_sendbuf,"MAIL FROM: <proxyscan@quakenet.org>\r\n");
75 psm_state = PSM_SENTFROM;
76
77 if (ps_flushbuf()) {
78 Error("proxyscan",ERR_DEBUG,"Error sending new mail to MTA.");
79 ps_mailconnect();
80 }
81 } else if (psm_state == PSM_NOTCONNECTED) {
82 /* Initiate connection */
83 ps_mailconnect();
84 } else {
85 Error("proxyscan",ERR_ERROR,"Unexpected happened: Not idle or disconnected but no mail outstanding?");
86 }
87 }
88
89 themail->next=mailqueue;
90 mailqueue=themail;
91}
92
93void psm_handler(int fd, short revents) {
94 char buf[256];
95 int res;
96 struct psmail *themail;
97
98 /* Error, abandon socket and reconnect if mail pending */
99 if (revents & (POLLERR | POLLHUP)) {
100 deregisterhandler(psm_mailerfd, 1);
101 psm_mailerfd=-1;
102 psm_state = PSM_NOTCONNECTED;
103 if (mailqueue)
104 ps_mailconnect();
105 return;
106 }
107
108 if (revents & POLLIN) {
109 /* Got some form of response.. */
110
111 res=read(fd, buf, 255);
112 if (res==0) {
113 /* Read EOF, not good - reconnect if mail is waiting */
114 deregisterhandler(psm_mailerfd, 1);
115 psm_mailerfd=-1;
116 psm_state = PSM_NOTCONNECTED;
117 if (mailqueue)
118 ps_mailconnect();
119 return;
120 }
121
122 if (res==-1) {
123 if (errno==EAGAIN || errno==EINPROGRESS) {
124 /* OK, ran out of data */
125 return;
126 }
127
128 /* otherwise, error */
129 deregisterhandler(psm_mailerfd, 1);
130 psm_state = PSM_NOTCONNECTED;
131 psm_mailerfd=-1;
132 if (mailqueue)
133 ps_mailconnect();
134
135 return;
136 }
137
138 /* OK, we got some actual response. Let's assume
139 * that it was an "OK" or similar. */
140
141 buf[res-1]='\0';
142 Error("proxyscan",ERR_DEBUG,"MTA response: %s",buf);
143
144 switch (psm_state) {
145 case PSM_CONNECTING:
146 /* Got banner, say HELO */
147 psm_sbufsize = sprintf(psm_sendbuf,"HELO %s\r\n",ps_mailname->content);
148 psm_state = PSM_SENTHELLO;
149 break;
150
151 case PSM_SENTHELLO:
152 /* Said HELLO, so announce mail */
153 if (!mailqueue) {
154 /* Should never happen */
155 psm_state = PSM_IDLE;
156 } else {
157 psm_sbufsize = sprintf(psm_sendbuf,"MAIL FROM: <proxyscan@quakenet.org>\r\n");
158 psm_state = PSM_SENTFROM;
159 }
160 break;
161
162 case PSM_SENTFROM:
163 /* Sent FROM, now TO */
164 psm_sbufsize = sprintf(psm_sendbuf,"RCPT TO: <splidge@quakenet.org>\r\n");
165 psm_state = PSM_SENTTO1;
166 break;
167
168 case PSM_SENTTO1:
169 /* Sent first TO, now the second one */
170 psm_sbufsize = sprintf(psm_sendbuf,"RCPT TO: <bopm@reports.blitzed.org>\r\n");
171 psm_state = PSM_SENTTO2;
172 break;
173
174 case PSM_SENTTO2:
175 /* Sent TO, now DATA */
176 psm_sbufsize = sprintf(psm_sendbuf,"DATA\r\n");
177 psm_state = PSM_SENTDATA;
178 break;
179
180 case PSM_SENTDATA:
181 /* Sent data, now send the body */
182 strcpy(psm_sendbuf, mailqueue->content);
183 psm_sbufsize=strlen(mailqueue->content);
184 psm_state = PSM_SENTBODY;
185 break;
186
187 case PSM_SENTBODY:
188 /* The body went through OK, so let's junk this mail and move onto the next one */
189 themail = mailqueue;
190 mailqueue=themail->next;
191 free(themail);
192
193 if (mailqueue) {
194 /* Mail waiting */
195 psm_sbufsize = sprintf(psm_sendbuf,"MAIL FROM: <proxyscan@quakenet.org>\r\n");
196 psm_state = PSM_SENTFROM;
197 } else {
198 psm_sbufsize=0;
199 psm_state = PSM_IDLE;
200 }
201
202 break;
203 }
204
205 /* If we generated a response, send it */
206 if (psm_sbufsize) {
207 if (ps_flushbuf()) {
208 /* We shouldn't ever get a "partial flush" so treat it as an error */
209 deregisterhandler(psm_mailerfd,1);
210 psm_state = PSM_NOTCONNECTED;
211 }
212 }
213 }
214}
215
216void ps_mailconnect() {
217 Error("proxyscan",ERR_INFO,"Attempting MTA connection to %s:%d",IPtostr(ps_mailip), ps_mailport);
218 psm_mailerfd=createconnectsocket(ps_mailip, ps_mailport);
219 psm_state = PSM_CONNECTING;
220 /* We wait for the connection banner */
221 registerhandler(psm_mailerfd,POLLIN,psm_handler);
222}
223
224/*
225 * ps_flushbuf(): tries to flush the write queue
226 *
227 * -1 : EOF or socket error
228 * 0 : All data flushed
229 * 1 : Partial data flushed
230 */
231
232int ps_flushbuf() {
233 int res;
234
235 if (psm_mailerfd==-1)
236 return -1;
237
238 res=write(psm_mailerfd, psm_sendbuf, psm_sbufsize);
239
240 if (res==0) {
241 /* EOF */
242 close(psm_mailerfd);
243 psm_mailerfd=-1;
244 return -1;
245 }
246
247 if (res==-1) {
248 if (errno==EAGAIN || errno==EINPROGRESS)
249 return 1;
250
251 close(psm_mailerfd);
252 psm_mailerfd=-1;
253 return -1;
254 }
255
256 if (res==psm_sbufsize) {
257 psm_sbufsize=0;
258 return 0;
259 }
260
261 /* Partial write */
262 memmove(psm_sendbuf, psm_sendbuf+res, psm_sbufsize-res);
263 psm_sbufsize-=res;
264
265 return 1;
266}