modules/pm/protocol_mirror.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. IS_Q_QUERY
  2. IS_G_QUERY
  3. IS_PERSISTENT
  4. parse_request
  5. 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_dictionary.h"
  46 #include "ca_macros.h"
  47 #include "ca_srcAttribs.h"
  48 
  49 #include "erroutines.h"
  50 
  51 #include "getopt.h"
  52 
  53 #define MIN_ARG_LENGTH  6
  54 #define NRTM_DELIM "-:"
  55 
  56 #define MAX_OPT_ARG_C 3
  57 
  58 #define Q_QUERY      0x00
  59 #define G_QUERY      0x01
  60 #define K_QUERY      0x02
  61 
  62 #define IS_Q_QUERY(a)          ((a)&Q_QUERY)
     /* [<][>][^][v][top][bottom][index][help] */
  63 #define IS_G_QUERY(a)          ((a)&G_QUERY)
     /* [<][>][^][v][top][bottom][index][help] */
  64 #define IS_PERSISTENT(a) ((a)&K_QUERY)
     /* [<][>][^][v][top][bottom][index][help] */
  65 
  66 
  67 /*
  68 * parses input and fills nrtm_q_t structure
  69 *
  70 * Returns:
  71 *  -1 in case of garbage
  72 *  0  in case of -q sources
  73 *  1  in case of valid -g
  74 *  2  in case of -k
  75 */
  76 static int parse_request(char *input, nrtm_q_t *nrtm_q)
     /* [<][>][^][v][top][bottom][index][help] */
  77 {
  78  int res=0, err=0;
  79  int opt_argc;
  80  int c;
  81  gchar **opt_argv;
  82  getopt_state_t *gst = NULL;
  83 
  84   /* Create the arguments. */
  85   /* This allows only a maximum of MAX_OPT_ARG_C words in the query. */
  86   opt_argv = g_strsplit(input, " ", MAX_OPT_ARG_C);
  87 
  88   /* Determine the number of arguments. */
  89   for (opt_argc=0; opt_argv[opt_argc] != NULL; opt_argc++);
  90 
  91   dieif( (gst = mg_new(0)) == NULL );
  92   
  93   while ((c = mg_getopt(opt_argc, opt_argv, "kq:g:", gst)) != EOF) 
  94   {
  95     switch (c) {
  96             case 'k':
  97                res |= K_QUERY; /* persistent connection */ 
  98             break;
  99 
 100             case 'q':
 101                 if (gst->optarg != NULL) {
 102                 char *token, *cursor = gst->optarg;
 103                    
 104                    res |= Q_QUERY;
 105                    err=strncmp(cursor, "sources", 7);
 106                    if(err!=0) break;
 107                    cursor+=7;
 108                    g_strchug(cursor);
 109                    token=cursor;
 110                    /* if no sourses are specified - put NULL in nrtm_q->source and list them all */
 111                    if ((*token=='\0') || (*token=='\n') || ((int)*token==13))nrtm_q->source=NULL;
 112                    else {
 113                      cursor=index(token, ' ');
 114                      if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
 115                      else {
 116                        cursor=index(token, 13); /* search for ctrl-M - telnet loves this */
 117                        if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
 118                        else {
 119                          cursor=index(token, '\n');
 120                          if (cursor) nrtm_q->source=g_strndup(token, (cursor-token));
 121                          else nrtm_q->source=g_strdup(token);
 122                        }
 123                      }
 124                    }
 125                 } else err=1;
 126             break;
 127 
 128             case 'g':
 129                 if (gst->optarg != NULL) {
 130                 char *token, *cursor = gst->optarg;
 131                 char **tokens;  
 132                 
 133                   res |= G_QUERY;
 134                   g_strdelimit(cursor, NRTM_DELIM, ':');
 135                   tokens=g_strsplit(cursor, ":", 4);
 136                   if(tokens==NULL) { err=1; break; }
 137  
 138                   if(tokens[0]) {
 139                   /* first token is source name */       
 140                      nrtm_q->source=g_strdup(tokens[0]);
 141                      if(tokens[1]) {
 142                     /* second token is version number */
 143                         nrtm_q->version=atoi(tokens[1]);
 144                         if(tokens[2]) {
 145                         /* this is first serial */      
 146                            nrtm_q->first=atol(tokens[2]);
 147                            if (nrtm_q->first>0) {
 148                               if(tokens[3]) {
 149                              /* this is last serial */
 150                                  nrtm_q->last=atol(tokens[3]);
 151                                  if (nrtm_q->last==0) 
 152                                  if (strncasecmp(tokens[3], "LAST", 4)!=0) err=1;
 153                               } else err=1;
 154                            } else err=1;    
 155                         } else err=1; 
 156                      } else err=1;  
 157                   } else err=1;   
 158                   g_strfreev(tokens);
 159  
 160                 } else err=1;
 161                 
 162             break;
 163             default:
 164                 err=1;
 165             break;
 166     } /* switch */
 167   } /* while there are arguments */
 168 
 169  free(gst);
 170 
 171  if (err) return(-1);
 172  else return(res); 
 173    
 174 }
 175 
 176 
 177 /* PM_interact() */
 178 /*++++++++++++++++++++++++++++++++++++++
 179   Interact with the client.
 180 
 181   int sock Socket that client is connected to.
 182 
 183   More:
 184   +html+ <PRE>
 185   Authors:
 186         ottrey
 187         andrei
 188 
 189   +html+ </PRE><DL COMPACT>
 190   +html+ <DT>Online References:
 191   +html+ <DD><UL>
 192   +html+ </UL></DL>
 193 
 194   ++++++++++++++++++++++++++++++++++++++*/
 195 void PM_interact(int sock) {
     /* [<][>][^][v][top][bottom][index][help] */
 196   char input[MAX_INPUT_SIZE];
 197   char buff[STR_L];
 198   ca_dbSource_t *source_hdl;
 199   int read_result;
 200   int parse_result;
 201   ip_addr_t address;
 202 
 203   char *hostaddress=NULL;
 204   sk_conn_st condat;
 205   nrtm_q_t nrtm_q;
 206   long current_serial;
 207   long oldest_serial;
 208   
 209   char *object;
 210   int operation;
 211   
 212   
 213   char *db_host;
 214   int  db_port;
 215   char *db_name;
 216   char *db_user;
 217   char *db_pswd;
 218 
 219   GString *gbuff;
 220   
 221   SQ_connection_t *sql_connection;     
 222   int persistent_connection;
 223 
 224   /* make a record for thread accounting */
 225   TA_add(sock, "nrtm_srv");
 226 
 227   
 228   /* Get the IP of the client */
 229   hostaddress = SK_getpeername(sock);
 230   
 231   /* initialise the connection structure */
 232   memset( &condat, 0, sizeof(sk_conn_st));
 233   /* initialise the nrtm structure */
 234   memset( &nrtm_q, 0, sizeof(nrtm_q_t));
 235   /* set the connection data: both rIP and eIP to real IP */
 236   condat.sock = sock;
 237   condat.ip = hostaddress;
 238   SK_getpeerip(sock, &(condat.rIP));
 239   memcpy( &(condat.eIP), &(condat.rIP), sizeof(ip_addr_t));
 240 
 241 
 242   /* Read input */
 243   read_result = SK_cd_gets(&(condat), input, MAX_INPUT_SIZE);
 244     
 245   /* read_result < 0 is an error and connection should be closed */
 246   if (read_result < 0 ) {
 247       /* log the fact, rtc was set */
 248   }
 249 
 250     
 251   parse_result = parse_request(input, &nrtm_q);
 252 
 253   
 254   if (parse_result < 0 ) {
 255       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Garbage received: %s", hostaddress, input);
 256       /* log the fact and exit */
 257       /* Free the hostaddress */
 258       sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
 259       SK_cd_puts(&condat, buff);
 260       SK_cd_close(&(condat));
 261       free(hostaddress);
 262       free(nrtm_q.source);
 263       return;
 264   }
 265   
 266   ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] -- input: [%s]", hostaddress, input); 
 267   
 268   /* this is -q sources query  - answer and return */    
 269   if (IS_Q_QUERY(parse_result)) {
 270           
 271       gbuff=PM_get_nrtm_sources(&(condat.rIP), nrtm_q.source);
 272       SK_cd_puts(&condat, gbuff->str);
 273       /* Free allocated memory  */
 274       g_string_free(gbuff, TRUE);
 275       free(hostaddress);
 276       free(nrtm_q.source);
 277       SK_cd_close(&(condat));
 278       return;
 279   }
 280   else if(IS_G_QUERY(parse_result)){
 281      if(IS_PERSISTENT(parse_result))persistent_connection=1; else persistent_connection=0;
 282   }
 283   else {
 284       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] -- Syntax error: %s", hostaddress, input);
 285       /* log the fact and exit */
 286       /* Free the hostaddress */
 287       sprintf(buff, "\n%%ERROR:1: Syntax error\n\n");
 288       SK_cd_puts(&condat, buff);
 289       SK_cd_close(&(condat));
 290       free(hostaddress);
 291       free(nrtm_q.source);
 292       return;
 293           
 294   }
 295   
 296   /* otherwise this is -g query */
 297   
 298   
 299   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);
 300    
 301   source_hdl = ca_get_SourceHandleByName(nrtm_q.source); 
 302   if (source_hdl == NULL){
 303      ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Unknown source %s", hostaddress, nrtm_q.source);
 304      sprintf(buff, "\n%%ERROR:4: Unknown source\n\n");
 305      SK_cd_puts(&condat, buff);
 306      free(hostaddress);
 307      free(nrtm_q.source);
 308      SK_cd_close(&(condat));
 309      return;
 310   }
 311          
 312   /* check if the client is authorized to mirror */
 313   SK_getpeerip(sock, &address);
 314   if(!AA_can_mirror(&address, nrtm_q.source)){
 315      ER_inf_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Not authorized to mirror the source %s", hostaddress, nrtm_q.source);
 316      sprintf(buff, "\n%%ERROR:3: You are not authorized to mirror the database\n\n");
 317      SK_cd_puts(&condat, buff);
 318      free(hostaddress);
 319      free(nrtm_q.source);
 320      SK_cd_close(&(condat));
 321      return;
 322   }
 323 
 324       
 325     
 326   /* get database */
 327   db_name = ca_get_srcdbname(source_hdl);
 328   /* get database host*/
 329   db_host = ca_get_srcdbmachine(source_hdl);      
 330   /* get database port*/
 331   db_port = ca_get_srcdbport(source_hdl);        
 332   /* get database user*/
 333   db_user = ca_get_srcdbuser(source_hdl);          
 334   /* get database password*/
 335   db_pswd = ca_get_srcdbpassword(source_hdl);
 336   
 337   sql_connection = SQ_get_connection(db_host, db_port,db_name, db_user, db_pswd);
 338   if(!sql_connection) {
 339       ER_perror(FAC_PM, PM_NOSQLC," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
 340       return;
 341   }
 342   ER_dbg_va(FAC_PM, ASP_PM_INPUT,"[%s] --  Made SQL connection to %s@%s", hostaddress, db_name, db_host); 
 343 
 344   /* free copies of the variables */
 345   free(db_host);
 346   free(db_name);
 347   free(db_user);
 348   free(db_pswd);
 349                                                         
 350   current_serial=PM_get_current_serial(sql_connection);
 351   oldest_serial=PM_get_oldest_serial(sql_connection);
 352     
 353   if((current_serial==-1) || (oldest_serial==-1)) {
 354       ER_perror(FAC_PM, PM_NOSERN," database='%s' [%d] %s",db_name, SQ_errno(sql_connection), SQ_error(sql_connection));
 355       /* Free the hostaddress */
 356       SK_cd_close(&(condat));
 357       /* close the connection to SQL server */
 358       SQ_close_connection(sql_connection); 
 359       free(hostaddress);
 360       free(nrtm_q.source);
 361       return;
 362   }
 363   
 364   /* zero indicates that LAST keyword has been used */    
 365   if(nrtm_q.last==0)nrtm_q.last=current_serial;
 366   /* for persistent connections end of range has no meaning */
 367   if(persistent_connection)nrtm_q.last=current_serial;
 368 
 369     
 370   if((nrtm_q.first>nrtm_q.last) || (nrtm_q.first<oldest_serial) || (nrtm_q.last>current_serial) ||
 371      (nrtm_q.first<=0) || (nrtm_q.last<=0) ) 
 372   {
 373       ER_dbg_va(FAC_PM, ASP_PM_ERESP,"[%s] --  Invalid range: %ld-%ld", hostaddress, nrtm_q.first, nrtm_q.last);
 374       /* write error message back to the client */
 375       sprintf(buff, "\n%%ERROR:2: Invalid range: Not within %ld-%ld\n\n", oldest_serial, current_serial);
 376       SK_cd_puts(&condat, buff);
 377       SK_cd_close(&(condat));
 378       
 379       /* close the connection to SQL server */
 380       SQ_close_connection(sql_connection); 
 381 
 382       /* Free the hostaddress */
 383       free(hostaddress);
 384       free(nrtm_q.source);
 385       return;
 386   }
 387   
 388   current_serial=nrtm_q.first;
 389  
 390   /* print banner */
 391   {
 392   /* get the header string */
 393   char *resp_header = ca_get_pw_resp_header;
 394 /*  sprintf(buff, "\n%% Rights restricted by copyright. See http://www.ripe.net/ripencc/pub-services/db/copyright.html\n\n"); */
 395   SK_cd_puts(&condat, "\n");
 396   SK_cd_puts(&condat, resp_header);
 397   free(resp_header);
 398   SK_cd_puts(&condat, "\n");
 399   } 
 400    
 401   sprintf(buff, "%%START Version: %d %s %ld-%ld\n\n", nrtm_q.version, nrtm_q.source, nrtm_q.first, nrtm_q.last);
 402   SK_cd_puts(&condat, buff);
 403 
 404   /* make a record for thread accounting */
 405   TA_setactivity(buff);
 406 
 407 /*************************** MAIN LOOP ****************************/   
 408 /* now start feeding client with data */    
 409   do {    
 410 
 411     object=PM_get_serial_object(sql_connection, current_serial, &operation);
 412     if (operation == OP_ADD) SK_cd_puts(&condat, "ADD\n\n");
 413     else SK_cd_puts(&condat, "DEL\n\n");
 414     
 415     SK_cd_puts(&condat, object);
 416 
 417     SK_cd_puts(&condat, "\n");
 418       
 419     free(object);
 420     current_serial++;
 421 
 422 /* for real-time mirroring we need some piece of code */
 423 if(persistent_connection && (condat.rtc == 0) )
 424 {
 425         while(((nrtm_q.last = PM_get_current_serial(sql_connection))<current_serial) 
 426                 && (CO_get_do_server()==1))sleep(1);
 427 }
 428 
 429   } /* do while there are more serials, connection was not reset and XXX do_server is on*/
 430    while((current_serial<=nrtm_q.last) && (condat.rtc == 0) && (CO_get_do_server()==1));
 431 /*******************************************************************/
 432   
 433   sprintf(buff, "%%END %s\n\n\n", nrtm_q.source);
 434   SK_cd_puts(&condat, buff);
 435 
 436   ER_inf_va(FAC_PM, ASP_PM_INPUT,"[%s] -- <%s:%ld-%ld (%ld)> ", 
 437            hostaddress, nrtm_q.source, nrtm_q.first, nrtm_q.last, nrtm_q.last-nrtm_q.first+1); 
 438 
 439   /* make a record for thread accounting */
 440   TA_delete();
 441 
 442   /* close the connection to SQL server */
 443   SQ_close_connection(sql_connection); 
 444   /* Free the hostaddress */
 445   free(hostaddress);
 446   free(nrtm_q.source);
 447 
 448   
 449   
 450 } /* PM_interact() */

/* [<][>][^][v][top][bottom][index][help] */