modules/pm/protocol_mirror.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- parse_request
- PM_interact
1 /***************************************
2
3 Protocol mirror module (pw).
4
5 Status: NOT REVUED, NOT TESTED
6
7 ******************/ /******************
8 Filename : protocol_mirror.c
9 Author : andrei
10 OSs Tested : Solaris
11 ******************/ /******************
12 Copyright (c) 2000 RIPE NCC
13
14 All Rights Reserved
15
16 Permission to use, copy, modify, and distribute this software and its
17 documentation for any purpose and without fee is hereby granted,
18 provided that the above copyright notice appear in all copies and that
19 both that copyright notice and this permission notice appear in
20 supporting documentation, and that the name of the author not be
21 used in advertising or publicity pertaining to distribution of the
22 software without specific, written prior permission.
23
24 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 ***************************************/
31 #include <stdio.h>
32 #include <glib.h>
33
34 #include "protocol_mirror.h"
35 #include "mysql_driver.h"
36 #include "constants.h"
37
38 //#include "access_control.h"
39 #include "sk.h"
40 #include "stubs.h"
41 #include "ud.h"
42 #include "ta.h"
43
44 #include "ca_configFns.h"
45 #include "ca_dictSyms.h"
46 #include "ca_macros.h"
47 #include "ca_srcAttribs.h"
48
49 #include "erroutines.h"
50
51 #define MIN_ARG_LENGTH 6
52 #define NRTM_DELIM "-:"
53 /*
54 * parses input and fills nrtm_q_t structure
55 *
56 * Returns:
57 * -1 in case of garbage
58 * 0 in case of valid -g
59 * 1 in case of -q sources
60 *
61 */
62 static int parse_request(char *input, nrtm_q_t *nrtm_q)
/* [<][>][^][v][top][bottom][index][help] */
63 {
64 char *ptr=input;
65 char *token;
66 char **tokens;
67 char **tokens2;
68 int res=0;
69
70 // return(-1);
71
72 if(strlen(input)<MIN_ARG_LENGTH) return(-1);
73 g_strchug(input);
74 res=strncmp(input, "-g", 2);
75 if(res!=0) {
76 /* may be this is -q source query */
77 res=strncmp(input, "-q", 2);
78 if(res!=0)return(-1);
79 ptr+=2;
80 g_strchug(ptr);
81 res=strncmp(ptr, "sources", 7);
82 if(res!=0)return(-1);
83 ptr+=7;
84 g_strchug(ptr);
85 token=ptr;
86 if ((*token=='\0') || (*token=='\n'))nrtm_q->source=NULL;
87 else {
88 ptr=index(token, ' ');
89 if (ptr) nrtm_q->source=g_strndup(token, (ptr-token));
90 else {
91 ptr=index(token, 13); /* search for ctrl-M - telnet loves this */
92 if (ptr) nrtm_q->source=g_strndup(token, (ptr-token));
93 else {
94 ptr=index(token, '\n');
95 if (ptr) nrtm_q->source=g_strndup(token, (ptr-token));
96 else
97 nrtm_q->source=g_strdup(token);
98 }
99 }
100 }
101 return(1);
102 }
103
104 /* this is -q query */
105 ptr+=2;
106
107
108 g_strchug(ptr);
109 g_strdelimit(ptr, NRTM_DELIM, ':');
110 tokens=g_strsplit(ptr, ":", 4);
111 if(tokens==NULL) return(-1);
112
113 if(tokens[0]) {
114 /* first token is source name */
115 nrtm_q->source=g_strdup(tokens[0]);
116 if(tokens[1]) {
117 /* second token is version number */
118 nrtm_q->version=atoi(tokens[1]);
119 if(tokens[2]) {
120 /* this is first serial */
121 nrtm_q->first=atol(tokens[2]);
122 if (nrtm_q->first>0) {
123 if(tokens[3]) {
124 /* this is last serial */
125 nrtm_q->last=atol(tokens[3]);
126 if (nrtm_q->last==0)
127 if (strncasecmp(tokens[3], "LAST", 4)!=0) res=-1;
128 } else res=-1;
129 } else res=-1;
130 } else res=-1;
131 } else res=-1;
132 } else res=-1;
133 g_strfreev(tokens);
134
135 return(res);
136 }
137
138
139 /* PM_interact() */
140 /*++++++++++++++++++++++++++++++++++++++
141 Interact with the client.
142
143 int sock Socket that client is connected to.
144
145 More:
146 +html+ <PRE>
147 Authors:
148 ottrey
149 andrei
150
151 +html+ </PRE><DL COMPACT>
152 +html+ <DT>Online References:
153 +html+ <DD><UL>
154 +html+ </UL></DL>
155
156 ++++++++++++++++++++++++++++++++++++++*/
157 void PM_interact(int sock) {
/* [<][>][^][v][top][bottom][index][help] */
158 char input[MAX_INPUT_SIZE];
159 char buff[STR_L];
160 ca_dbSource_t *source_hdl;
161 int read_result;
162 int parse_result;
163 ip_addr_t address;
164
165 char *hostaddress=NULL;
166 sk_conn_st condat;
167 nrtm_q_t nrtm_q;
168 long current_serial;
169 long oldest_serial;
170
171 char *object;
172 int operation;
173
174
175 char *db_host;
176 int db_port;
177 char *db_name;
178 char *db_user;
179 char *db_pswd;
180
181 GString *gbuff;
182
183 SQ_connection_t *sql_connection;
184
185 /* make a record for thread accounting */
186 TA_add(sock, "nrtm_srv");
187
188
189 /* Get the IP of the client */
190 hostaddress = SK_getpeername(sock);
191
192 /* initialise the connection structure */
193 memset( &condat, 0, sizeof(sk_conn_st));
194 /* initialise the nrtm structure */
195 memset( &nrtm_q, 0, sizeof(nrtm_q_t));
196 /* set the connection data: both rIP and eIP to real IP */
197 condat.sock = sock;
198 condat.ip = hostaddress;
199 SK_getpeerip(sock, &(condat.rIP));
200 memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t));
201
202
203 /* Read input */
204 read_result = SK_cd_gets(&(condat), input, MAX_INPUT_SIZE);
205
206 /* read_result < 0 is an error and connection should be closed */
207 if (read_result < 0 ) {
208 /* log the fact, rtc was set */
209 }
210
211
212 parse_result = parse_request(input, &nrtm_q);
213
214
215 if (parse_result < 0 ) {
216 ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Garbage received: %s", hostaddress, input);
217 /* log the fact and exit */
218 /* Free the hostaddress */
219 sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
220 SK_cd_puts(&condat, buff);
221 SK_cd_close(&(condat));
222 free(hostaddress);
223 free(nrtm_q.source);
224 return;
225 }
226
227 ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input: [%s]", hostaddress, input);
228
229 if (parse_result == 1 ) {
230
231 gbuff=PM_get_nrtm_sources(&(condat.rIP), nrtm_q.source);
232 SK_cd_puts(&condat, gbuff->str);
233 /* Free allocated memory */
234 g_string_free(gbuff, TRUE);
235 free(hostaddress);
236 free(nrtm_q.source);
237 SK_cd_close(&(condat));
238 return;
239 }
240
241 ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input parsed: %s:%d:%ld-%ld", hostaddress, nrtm_q.source, nrtm_q.version, nrtm_q.first, nrtm_q.last);
242
243 source_hdl = ca_get_SourceHandleByName(nrtm_q.source);
244 if (source_hdl == NULL){
245 ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Unknown source %s", hostaddress, nrtm_q.source);
246 sprintf(buff, "\n%%ERROR:4: Unknown source\n\n");
247 SK_cd_puts(&condat, buff);
248 free(hostaddress);
249 free(nrtm_q.source);
250 SK_cd_close(&(condat));
251 return;
252 }
253
254 /* check if the client is authorized to mirror */
255 SK_getpeerip(sock, &address);
256 if(!AA_can_mirror(&address, nrtm_q.source)){
257 ER_inf_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Not authorized to mirror the source %s", hostaddress, nrtm_q.source);
258 sprintf(buff, "\n%%ERROR:3: You are not authorized to mirror the database\n\n");
259 SK_cd_puts(&condat, buff);
260 free(hostaddress);
261 free(nrtm_q.source);
262 SK_cd_close(&(condat));
263 return;
264 }
265
266
267
268 /* get database */
269 db_name = ca_get_srcdbname(source_hdl);
270 /* get database host*/
271 db_host = ca_get_srcdbmachine(source_hdl);
272 /* get database port*/
273 db_port = ca_get_srcdbport(source_hdl);
274 /* get database user*/
275 db_user = ca_get_srcdbuser(source_hdl);
276 /* get database password*/
277 db_pswd = ca_get_srcdbpassword(source_hdl);
278
279 sql_connection = SQ_get_connection(db_host, db_port,db_name, db_user, db_pswd);
280 if(!sql_connection) {
281 ER_perror(FAC_PM, PM_NOSQLC," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
282 return;
283 }
284 ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- Made SQL connection to %s@%s", hostaddress, db_name, db_host);
285
286 /* free copies of the variables */
287 free(db_host);
288 free(db_name);
289 free(db_user);
290 free(db_pswd);
291
292 current_serial=PM_get_current_serial(sql_connection);
293 oldest_serial=PM_get_oldest_serial(sql_connection);
294
295 if((current_serial==-1) || (oldest_serial==-1)) {
296 ER_perror(FAC_PM, PM_NOSERN," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
297 /* Free the hostaddress */
298 SK_cd_close(&(condat));
299 /* close the connection to SQL server */
300 SQ_close_connection(sql_connection);
301 free(hostaddress);
302 free(nrtm_q.source);
303 return;
304 }
305
306 /* zero indicates that LAST keyword has been used */
307 if(nrtm_q.last==0)nrtm_q.last=current_serial;
308
309
310 if((nrtm_q.first>nrtm_q.last) || (nrtm_q.first<oldest_serial) || (nrtm_q.last>current_serial) ||
311 (nrtm_q.first<=0) || (nrtm_q.last<=0) )
312 {
313 ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Invalid range: %ld-%ld", hostaddress, nrtm_q.first, nrtm_q.last);
314 /* write error message back to the client */
315 sprintf(buff, "\n%%ERROR:2: Invalid range: Not within %ld-%ld\n\n", oldest_serial, current_serial);
316 SK_cd_puts(&condat, buff);
317 SK_cd_close(&(condat));
318
319 /* close the connection to SQL server */
320 SQ_close_connection(sql_connection);
321
322 /* Free the hostaddress */
323 free(hostaddress);
324 free(nrtm_q.source);
325 return;
326 }
327
328 current_serial=nrtm_q.first;
329
330 /* print banner */
331 {
332 /* get the header string */
333 char *resp_header = ca_get_pw_resp_header;
334 /* sprintf(buff, "\n%% Rights restricted by copyright. See http://www.ripe.net/ripencc/pub-services/db/copyright.html\n\n"); */
335 SK_cd_puts(&condat, resp_header);
336 free(resp_header);
337 SK_cd_puts(&condat, "\n");
338 }
339
340 sprintf(buff, "%%START Version: %d %s %ld-%ld\n", nrtm_q.version, nrtm_q.source, nrtm_q.first, nrtm_q.last);
341 SK_cd_puts(&condat, buff);
342
343 /* make a record for thread accounting */
344 TA_setactivity(buff);
345
346 /* now start feeding client with data */
347 do {
348
349 object=PM_get_serial_object(sql_connection, current_serial, &operation);
350 if (operation == OP_ADD) SK_cd_puts(&condat, "\nADD\n\n");
351 else SK_cd_puts(&condat, "\nDEL\n\n");
352
353 SK_cd_puts(&condat, object);
354
355 free(object);
356 current_serial++;
357
358
359 } /* do while there are more serials, connection was not reset and XXX do_server is on*/
360 while((current_serial<=nrtm_q.last) && (condat.rtc == 0));
361
362
363 sprintf(buff, "\n%%END %s\n\n", nrtm_q.source);
364 SK_cd_puts(&condat, buff);
365
366 ER_inf_va(FAC_PM, ASP_PM_INPUT,"[%s] -- <%s:%ld-%ld (%ld)> ",
367 hostaddress, nrtm_q.source, nrtm_q.first, nrtm_q.last, nrtm_q.last-nrtm_q.first+1);
368
369 /* make a record for thread accounting */
370 TA_delete();
371
372 SK_cd_close(&(condat));
373
374 /* close the connection to SQL server */
375 SQ_close_connection(sql_connection);
376 /* Free the hostaddress */
377 free(hostaddress);
378 free(nrtm_q.source);
379
380
381
382 } /* PM_interact() */