Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

packets_operations.c

Go to the documentation of this file.
00001 /*! \file packets_operations.c
00002           This file implements output packet mechanism (OFFER, ACK or INFORM).
00003  */
00004 
00005 #include "server_config.h" 
00006 #include "packets_operations.h"
00007 #include "dhcp.h"
00008 
00009 
00010 
00011 
00012 static void clear_profile (struct opt *options);
00013 static int add_option_to_profile (struct opt *mprofile, int option, char *type, char *value, int len);
00014 static int remove_option_from_profile (struct opt *mprofile, int option);
00015 static void context2profile (struct opt *profile, struct mysql_tables *mysql_tables);
00016 
00017 
00018 
00019 
00020 
00021 /*! \brief Global DHCP configuration handler.
00022  */
00023 
00024 extern struct global_config configuration_globale;
00025 
00026 /*! \brief Reset option profile to "all zeros".
00027     \author Denis BEURIVE
00028     \param options Pointer to a destination 'opt' data structure to reset.
00029     \warning The pointer 'options' should point to an array which contains at least MAX_PROFILE_OPTIONS
00030              (which should be greater than 256) elements.
00031  */
00032 
00033 static void clear_profile (struct opt *options)
00034 {
00035   int i;
00036 
00037   for (i=0; i<MAX_PROFILE_OPTIONS; i++)
00038   {
00039     options[i].code = 0;
00040     options[i].len  = 0;
00041     memset ((void*)(options[i]).value, 0, VALUE_MAX_SIZE);
00042   }
00043 }
00044 
00045 /*! \brief Add an option to the loaded profile.
00046     \author Denis BEURIVE
00047     \param mprofile Pointer to an array of 'opt' data structures that represents the profile to manipulate.
00048     \param option Option's code (between 1 and 254 included).
00049     \param type Pointer to a zero terminated string of characters the represents the type of value.
00050            Type could be:
00051                 <UL>
00052                     <LI>"UINT32" (values are separated by ':')
00053                     <LI>"UINT16" (values are separated by ':')
00054                     <LI>"IP" (values are separated by ':')
00055                     <LI>"HEXA-BYTE"
00056                     <LI>"ASCII-BYTE"
00057                 </UL>
00058     \param value Pointer to the value. The format of the value depends on its type.
00059     \param len Number of bytes of the value.
00060     \return Upon successful completion, the function returns the value 0.
00061             Otherwize, the function returns the value 1.
00062  */
00063 
00064 static int add_option_to_profile (struct opt *mprofile, int option, char *type, char *value, int len)
00065 {
00066     int         converted;
00067 
00068     /* ------------------------------------------------- */
00069     /* Sanity check                                      */
00070     /* ------------------------------------------------- */
00071 
00072     if ((option > 254) || (option < 1))
00073     {
00074        my_syslog (configuration_globale.log_file,
00075                   "[INTERNAL ERROR] [%s:%d] add_option_to_profile: invalid option's value (%d)",
00076                   __FILE__, __LINE__,
00077                   option);
00078        return 1;
00079     }
00080 
00081     converted = 0;
00082 
00083     if (strcmp(type, "UINT32") == 0)
00084     {
00085       int rc = uint32_to_network_byte_order (value, (mprofile[option]).value, VALUE_MAX_SIZE);
00086       if (rc == -1) { return 1; }
00087       (mprofile[option]).len = rc * 4;
00088       (mprofile[option]).code = option;
00089       converted = 1;
00090     }
00091 
00092     if (strcmp(type, "UINT16") == 0)
00093     {
00094       int rc = uint16_to_network_byte_order (value, (mprofile[option]).value, VALUE_MAX_SIZE);
00095       if (rc == -1) { return 1; }
00096       (mprofile[option]).len = rc * 2;
00097       (mprofile[option]).code = option;
00098       converted = 1;
00099     }
00100 
00101     if (strcmp(type, "HEXA-BYTE") == 0)
00102     {
00103       int rc = hexa_to_binary (value, (mprofile[option]).value, VALUE_MAX_SIZE);
00104       if (rc == -1) { return 1; }
00105       (mprofile[option]).len = rc;
00106       (mprofile[option]).code = option;
00107       converted = 1;
00108     }
00109 
00110     if (strcmp(type, "ASCII-BYTE") == 0)
00111     {
00112       int rc = ascii_to_binary (value, (mprofile[option]).value, len, VALUE_MAX_SIZE);
00113       if (rc == -1) { return 1; }
00114       (mprofile[option]).len = rc;
00115       (mprofile[option]).code = option;
00116       converted = 1;
00117     }
00118 
00119     if (strcmp(type, "IP") == 0)
00120     {
00121       int rc = ip_to_network_byte_order (value, (mprofile[option]).value, VALUE_MAX_SIZE);
00122       if (rc == -1) { return 1; }
00123       (mprofile[option]).len = rc * 4;
00124       (mprofile[option]).code = option;
00125       converted = 1;
00126     }
00127 
00128     if (converted == 0)
00129     {
00130       my_syslog (configuration_globale.log_file,
00131                  "[ERROR] [%s:%d] Invalid option type (%s) for option", __FILE__, __LINE__, type);
00132       return 1;
00133     }
00134 
00135     return 0;
00136 }
00137 
00138 /*! \brief Remove an option from the loaded profile.
00139     \author Denis BEURIVE
00140     \param mprofile Pointer to an array of 'opt' data structures that represents the profile to manipulate.
00141     \param option Option's code (between 1 and 254 included).
00142     \return Upon successful completion, the function returns the value 0.
00143             Otherwize, the function returns the value 1.
00144  */
00145 
00146 static int remove_option_from_profile (struct opt *mprofile, int option)
00147 {
00148     if ((option > 254) || (option < 1))
00149     {
00150        my_syslog (configuration_globale.log_file,
00151        "[INTERNAL ERROR] [%s:%d] remove_option_from_profile: invalid option's value (%d)",
00152        __FILE__, __LINE__,
00153        option);
00154        return 1;
00155     }
00156 
00157     (mprofile[option]).code = 0;
00158     (mprofile[option]).len  = 0;
00159 
00160     memset ((void*)(mprofile[option]).value, 0, VALUE_MAX_SIZE);
00161 
00162     return 0;
00163 }
00164 
00165 /*! \brief Copy the options' profile extracted from the client's context into a 'opt' data structure (used
00166            to assemble the output DHCP packet).
00167     \author Denis BEURIVE
00168     \param profile Pointer to a destination 'opt' data structure.
00169     \param mysql_tables Pointer to a 'mysql_tables' data structure that contains the client's context (loaded
00170            form the database).
00171     \remark Types of options' values can be:
00172             <UL>
00173                 <LI>"UINT32" (one or more values, separated by ':')
00174                 <LI>"UINT16" (one or more values, separated by ':')
00175                 <LI>"IP" (one or more values, separated by ':')
00176                 <LI>"HEXA-BYTE"
00177                 <LI>"ASCII-BYTE"
00178             </UL>
00179     \warning The pointer 'options' should point to an array which contains at least MAX_PROFILE_OPTIONS
00180              (which should be greater than 256) elements.
00181  */
00182 
00183 static void context2profile (struct opt *profile, struct mysql_tables *mysql_tables)
00184 {
00185   int  i, code, converted;
00186   char *type;
00187   char *value;
00188 
00189 
00190   clear_profile (profile);
00191 
00192   /* --------------------------------------------------- */
00193   /* Convert all values to the correct internal format   */
00194   /* --------------------------------------------------- */
00195 
00196   for (i=0; i<mysql_tables->option_number; i++)
00197   {
00198     code = (int)(((mysql_tables->options)[i]).option_code);
00199 
00200     /* ------------------------------------------------- */
00201     /* Sanity check                                      */
00202     /* ------------------------------------------------- */
00203 
00204     if ((code > 254) || (code < 1))
00205     {
00206       my_syslog (configuration_globale.log_file,
00207                  "[WARNING] [%s:%d] Invalid option code (%u) for profile_optionnel=[%s], SKIP",
00208                  __FILE__, __LINE__,
00209                  code,
00210                  ((mysql_tables->options)[i]).profile_optionnel);
00211       continue;
00212     }
00213 
00214     /* ------------------------------------------------- */
00215     /* 'option_value' needs to be interpreted depending  */
00216     /* on the value of 'option_type'.                    */
00217     /* The following code set the following values :     */
00218     /*      + (profile[code]).code                       */ 
00219     /*      + (profile[code]).len                        */
00220     /*      + (profile[code]).value.                     */
00221     /* ------------------------------------------------- */
00222 
00223     type  = ((mysql_tables->options)[i]).option_type;
00224     value = ((mysql_tables->options)[i]).option_value;
00225 
00226     converted = 0;
00227 
00228     if (strcmp(type, "UINT32") == 0)
00229     {
00230       int rc = uint32_to_network_byte_order (value, (profile[code]).value, VALUE_MAX_SIZE);
00231       if (rc == -1) { continue; }
00232       (profile[code]).len = rc * 4;
00233       (profile[code]).code = code;
00234       converted = 1;
00235     }
00236 
00237     if (strcmp(type, "UINT16") == 0)
00238     {
00239       int rc = uint16_to_network_byte_order (value, (profile[code]).value, VALUE_MAX_SIZE);
00240       if (rc == -1) { continue; }
00241       (profile[code]).len = rc * 2;
00242       (profile[code]).code = code;
00243       converted = 1;
00244     }
00245 
00246     if (strcmp(type, "HEXA-BYTE") == 0)
00247     {
00248       int rc = hexa_to_binary (value, (profile[code]).value, VALUE_MAX_SIZE);
00249       if (rc == -1) { continue; }
00250       (profile[code]).len = rc;
00251       (profile[code]).code = code;
00252       converted = 1;
00253     }
00254 
00255     if (strcmp(type, "ASCII-BYTE") == 0)
00256     {
00257       int rc = ascii_to_binary (value, (profile[code]).value, strlen(value), VALUE_MAX_SIZE);
00258       if (rc == -1) { continue; }
00259       (profile[code]).len = rc;
00260       (profile[code]).code = code;
00261       converted = 1;
00262     }
00263 
00264     if (strcmp(type, "IP") == 0)
00265     {
00266       int rc = ip_to_network_byte_order (value, (profile[code]).value, VALUE_MAX_SIZE);
00267       if (rc == -1) { continue; }
00268       (profile[code]).len = rc * 4;
00269       (profile[code]).code = code;
00270       converted = 1;
00271     }
00272 
00273     if (converted == 0)
00274     {
00275       my_syslog (configuration_globale.log_file,
00276                  "[WARNING] [%s:%d] Invalid option type (%s) for profile [%s], ignore",
00277                  __FILE__, __LINE__,
00278                  type,
00279                  ((mysql_tables->options)[i]).profile_optionnel);
00280       continue;
00281     }
00282   }
00283 }
00284 
00285 /*! \brief Send a DHCPOFFER and log the output packet.
00286     \author Denis BEURIVE
00287     \param p Pointer to the incoming packet (should be a DHCP DISCOVER).
00288     \param mysql_tables pointer to a 'mysql_tables' data structure that contains the loaded client's context.
00289     \param ip Pointer to a zero terminated string of characters that represents the IP address of the user.
00290     \param broadcast 4 bytes long integer that contains the binary representation (in network byte order)
00291            of the broadcast IP address.
00292     \param server_ip 4 bytes long integer that contains the binary representation (in network byte order)
00293            of the server IP address.
00294     \param socket_desc Socket descriptor of the DHCP server.
00295     \param client_address Pointer to a 'sockaddr_in' data structure that contains the internet address
00296            of the incoming packet's sender.
00297            If the configuration tag 'enable-broadcast-responses' is set to "yes", then the parameter
00298            'client_address' is never used (since the server always send broadcasts).
00299     \param tip Flag that indicates wether the IP address should be taken from the STATIC pool or the
00300            dynamic pool. Values can be:
00301            <ul>
00302               <li>STATIC_IP (extracted from mysql_tables->abonne_ip.)
00303               <li>DYNAMIC_IP (extracted from mysql_tables->ip_lease.)
00304            </ul>
00305     \return Upon successful completion, the function returns the value 0.
00306             Otherwise, the function returns the value 1.
00307  */
00308 
00309 int packets_send_offer (
00310                          struct dhcp_packet    *p,
00311                          struct mysql_tables   *mysql_tables,
00312                          char                  *ip,
00313                          unsigned long int     broadcast,
00314                          unsigned long int     server_ip,
00315                          int                   socket_desc,
00316                          struct sockaddr_in    *client_address,
00317                          int                   tip)
00318 {
00319   struct dhcp_packet     packet_out;
00320   struct sockaddr_in     addr_target;
00321   int                    adress_size, rc, i;
00322   char                   *serverip;
00323   struct opt             options[MAX_PROFILE_OPTIONS];
00324 
00325 
00326 
00327   packets_clear (&packet_out);
00328   serverip = configuration_globale.server_ip_seen_by_client;
00329 
00330   /* ------------------------------------------------------------ */
00331   /* Transfert options from loaded profile (from database) into   */
00332   /* internal profile representation.                             */
00333   /* ------------------------------------------------------------ */
00334 
00335   context2profile (options, mysql_tables);
00336 
00337   /* ------------------------------------------------------------ */
00338   /* Format the OFFER                                             */
00339   /* Notes:                                                       */
00340   /* - We don't set 'ciaddr' -> This field will be all zero.      */
00341   /* - We don't set, 'sname' and 'file' are all zero.             */
00342   /* ------------------------------------------------------------ */
00343 
00344   packets_set_op           (&packet_out, BOOTREPLY);
00345   packets_set_htype        (&packet_out, packets_get_htype(p));
00346   packets_set_hlen         (&packet_out, packets_get_hlen(p));
00347   packets_set_hops         (&packet_out, 0);
00348   packets_set_xid          (&packet_out, packets_get_xid(p));
00349   packets_set_secs         (&packet_out, packets_get_secs(p));
00350   packets_set_flags        (&packet_out, packets_get_flags(p));
00351   packets_set_yiaddr       (&packet_out, ip);
00352   packets_set_siaddr       (&packet_out, configuration_globale.server_ip_seen_by_client);
00353   packets_set_bin_giaddr   (&packet_out, packets_get_bin_giaddr(p));
00354   packets_set_chaddr       (&packet_out, packets_get_bin_chaddr(p));
00355 
00356   /* ------------------------------------------------------------ */
00357   /* Set the correct options' profile                             */
00358   /*    - lease (already in loaded profile)                       */
00359   /*    - routers (already in loaded profile)                     */
00360   /*    - domain name (already in loaded profile)                 */
00361   /*    - domain name server (already in loaded profile)          */
00362   /*    - subnet mask (already in loaded profile)                 */
00363   /*    - message type (added)                                    */
00364   /*    - server identifier (added)                               */
00365   /* ------------------------------------------------------------ */
00366 
00367   if (configuration_globale.debug > 1)
00368   {
00369     my_syslog (configuration_globale.log_file,
00370     "[DEBUG] [%s:%d] Add options to DHCP packets", __FILE__, __LINE__);
00371   }
00372 
00373   /* Message type */
00374   add_option_to_profile (options, 53, "HEXA-BYTE", DHCPOFFER_HEXA,     strlen(DHCPOFFER_HEXA)); 
00375 
00376   /* Server identifier */
00377   add_option_to_profile (options, 54, "IP",        serverip,           strlen(serverip)); 
00378 
00379   /* ------------------------------------------------------------ */
00380   /* if STATIC,                                                   */
00381   /* get gateway from "mysql_tables->abonne_ip.gateway"           */
00382   /* if DYNAMIC,                                                  */
00383   /* get gateway from "mysql_tables->ip_lease.gateway"            */
00384   /* ------------------------------------------------------------ */
00385 
00386   if (configuration_globale.debug > 1)
00387   { my_syslog (configuration_globale.log_file,
00388     "[DEBUG] [%s:%d] tip = %d",
00389     __FILE__, __LINE__,
00390     tip);
00391   }
00392 
00393   if (tip == STATIC_IP)
00394   {
00395     add_option_to_profile (options, 3, "IP", mysql_tables->abonne_ip.gateway, 
00396                            strlen(mysql_tables->abonne_ip.gateway)); 
00397     add_option_to_profile (options, 1, "IP", mysql_tables->abonne_ip.subnet,
00398                            strlen(mysql_tables->abonne_ip.subnet));
00399 
00400     if (configuration_globale.debug > 1) 
00401     { my_syslog (configuration_globale.log_file,
00402       "[DEBUG] [%s:%d] packets_send_offer: Add gateway and subnet %s %s", 
00403       __FILE__, __LINE__,
00404       mysql_tables->abonne_ip.gateway,
00405       mysql_tables->abonne_ip.subnet); }
00406   }
00407 
00408   if (tip == DYNAMIC_IP)
00409   {
00410     add_option_to_profile (options, 3, "IP", mysql_tables->ip_lease.gateway,
00411                            strlen(mysql_tables->ip_lease.gateway));
00412     add_option_to_profile (options, 1, "IP", mysql_tables->ip_lease.subnet,
00413                            strlen(mysql_tables->ip_lease.subnet));
00414     if (configuration_globale.debug > 1)
00415     { my_syslog (configuration_globale.log_file,
00416       "[DEBUG] [%s:%d] packets_send_offer: Add gateway and subnet %s %s",
00417       __FILE__, __LINE__,
00418       mysql_tables->ip_lease.gateway,
00419       mysql_tables->ip_lease.subnet); }
00420   }
00421 
00422   /* ------------------------------------------------------------ */
00423   /* Write packet's options                                       */
00424   /* ------------------------------------------------------------ */
00425 
00426   for (i=1; i<255; i++)
00427   {
00428     if ((options[i]).code != 0)
00429     {
00430        packets_set_option (&packet_out, i, (options[i]).value, (options[i]).len);
00431        if (configuration_globale.debug > 1)
00432        { my_syslog (configuration_globale.log_file,
00433          "[DEBUG] [%s:%d] packets_send_offer: Adding option %d", __FILE__, __LINE__, i); }
00434     }
00435   }
00436 
00437   packets_close_option (&packet_out);
00438 
00439   /* ------------------------------------------------------------ */
00440   /* Send it                                                      */
00441   /* ------------------------------------------------------------ */
00442 
00443   adress_size = sizeof (struct sockaddr);
00444   memset ((void*)&addr_target, 0, sizeof(struct sockaddr_in));
00445 
00446   if (configuration_globale.broadcast_mode == 1)
00447   {
00448     addr_target.sin_family        = AF_INET;
00449     addr_target.sin_port          = htons(TARGET_PORT);
00450     (addr_target.sin_addr).s_addr = broadcast;
00451   }
00452   else
00453   { memcpy ((void*)&addr_target, (void*)client_address, sizeof(struct sockaddr_in)); }
00454 
00455   if (configuration_globale.debug > 0)
00456   { my_syslog (configuration_globale.log_file,
00457     "[DEBUG] [%s:%d] packets_send_offer: Sending DHCP OFFER for xid %u",
00458     __FILE__, __LINE__, packets_get_xid(p)); }
00459 
00460   if (configuration_globale.dumper_mode > 0)
00461   { packet_dump (&packet_out, configuration_globale.debug_file, configuration_globale.csv_file, NULL, &addr_target); }
00462 
00463   #ifndef READ_PACKET_FROM_FILE
00464 
00465     rc = sendto (
00466                   socket_desc,
00467                   (void*)&packet_out,
00468                   packet_out.ctrl.taille,
00469                   0,
00470                   (struct sockaddr*)&addr_target,
00471                   adress_size
00472                 );
00473   
00474     if (rc == -1)
00475     {
00476       my_syslog (configuration_globale.log_file,
00477                  "[WARNING] [%s:%d] Could not send OFFER for xid %u - %s",
00478                  __FILE__, __LINE__,
00479                  packets_get_xid(p),
00480                  strerror(errno));
00481       return 1;
00482     }
00483 
00484   #else
00485 
00486     my_syslog (configuration_globale.log_file,
00487                "[INFO] [%s:%d] Reading packet from file => packet no sent (this is normal)",
00488                __FILE__, __LINE__);
00489 
00490   #endif
00491 
00492   return 0;
00493 }
00494 
00495 /*! \brief Send a DHCPACK in response to a REQUEST and log the output packet.
00496     \author Denis BEURIVE
00497     \param p Pointer to the incoming packet (should be a DHCP REQUEST).
00498     \param mysql_tables pointer to a 'mysql_tables' data structure that contains the loaded client's
00499            context.
00500     \param ip Pointer to a zero terminated string of characters that represents the client's IP address. 
00501     \param broadcast 4 bytes long integer that contains the binary representation (in network byte order) of
00502            the broadcast IP address.
00503     \param server_ip 4 bytes long integer that contains the binary representation (in network byte order) of
00504            the server IP address.
00505     \param socket_desc Socket descriptor of the DHCP server.
00506     \param client_address Pointer to a 'sockaddr_in' data structure that contains the internet address of the
00507            incoming packet's sender.
00508            If the configuration tag 'enable-broadcast-responses' is set to "yes", then the parameter
00509            'client_address' is never used (since the server always sends broadcasts).
00510     \param tip Flag that indicates wether the IP address should be taken from the STATIC pool or the
00511            dynamic pool. Values can be:
00512            <ul>
00513               <li>STATIC_IP (extracted from mysql_tables->abonne_ip.)
00514               <li>DYNAMIC_IP (extracted from mysql_tables->ip_lease.)
00515            </ul>
00516     \return Upon successful completion, the function returns the value 0.
00517             Otherwise, the function returns the value 1.
00518  */
00519 
00520 int packets_send_ack (
00521                          struct dhcp_packet    *p,
00522                          struct mysql_tables   *mysql_tables,
00523                          char                  *ip,
00524                          unsigned long int     broadcast,
00525                          unsigned long int     server_ip,
00526                          int                   socket_desc,
00527                          struct sockaddr_in    *client_address,
00528                          int                   tip)
00529 {
00530   struct dhcp_packet     packet_out;
00531   struct sockaddr_in     addr_target;
00532   int                    adress_size, rc, i;
00533   char                   *serverip;
00534   struct opt             options[MAX_PROFILE_OPTIONS];
00535 
00536 
00537   packets_clear (&packet_out);
00538   serverip = configuration_globale.server_ip_seen_by_client;
00539 
00540   /* ------------------------------------------------------------ */
00541   /* Transfert options from loaded profile (from database) into   */
00542   /* internal profile representation.                             */
00543   /* ------------------------------------------------------------ */
00544 
00545   context2profile (options, mysql_tables);
00546 
00547   /* ------------------------------------------------------------ */
00548   /* Format the ACK                                               */
00549   /* Notes:                                                       */
00550   /* - We don't set, 'sname' and 'file' are all zero.             */
00551   /* ------------------------------------------------------------ */
00552 
00553   packets_set_op           (&packet_out, BOOTREPLY);
00554   packets_set_htype        (&packet_out, packets_get_htype(p));
00555   packets_set_hlen         (&packet_out, packets_get_hlen(p));
00556   packets_set_hops         (&packet_out, 0);
00557   packets_set_xid          (&packet_out, packets_get_xid(p));
00558   packets_set_secs         (&packet_out, packets_get_secs(p));
00559   packets_set_flags        (&packet_out, packets_get_flags(p));
00560   packets_set_yiaddr       (&packet_out, ip);
00561   packets_set_siaddr       (&packet_out, configuration_globale.server_ip_seen_by_client);
00562   packets_set_bin_giaddr   (&packet_out, packets_get_bin_giaddr(p));
00563   packets_set_bin_ciaddr   (&packet_out, packets_get_bin_ciaddr(p));
00564   packets_set_chaddr       (&packet_out, packets_get_bin_chaddr(p));
00565 
00566   /* ------------------------------------------------------------ */
00567   /* Set the correct options' profile                             */
00568   /*    - lease (already in loaded profile)                       */
00569   /*    - routers (already in loaded profile)                     */
00570   /*    - domain name (already in loaded profile)                 */
00571   /*    - domain name server (already in loaded profile)          */
00572   /*    - subnet mask (already in loaded profile)                 */
00573   /*    - message type (added)                                    */
00574   /*    - server identifier (added)                               */
00575   /* ------------------------------------------------------------ */
00576 
00577   if (configuration_globale.debug > 1)
00578   { my_syslog (configuration_globale.log_file,
00579                "[DEBUG] [%s:%d] packets_send_ack: Add option 53 (message type) = 3",
00580                __FILE__, __LINE__); }
00581 
00582   /* Message type */ 
00583   add_option_to_profile (options, 53, "HEXA-BYTE", DHCPACK_HEXA, strlen(DHCPACK_HEXA)); 
00584 
00585   if (configuration_globale.debug > 1)
00586   { my_syslog (configuration_globale.log_file,
00587                "[DEBUG] [%s:%d] packets_send_ack: Add option 54 (server ID) %s",
00588                __FILE__, __LINE__, serverip); }
00589 
00590   /* Server Identifier */
00591   add_option_to_profile (options, 54, "IP", serverip, strlen(serverip)); 
00592 
00593   /* ------------------------------------------------------------ */
00594   /* if STATIC,                                                   */
00595   /* get gateway from "mysql_tables->abonne_ip.gateway"           */
00596   /* if DYNAMIC,                                                  */
00597   /* get gateway from "mysql_tables->ip_lease.gateway"            */
00598   /* ------------------------------------------------------------ */
00599 
00600   if (configuration_globale.debug > 1)
00601   { my_syslog (configuration_globale.log_file,
00602     "[DEBUG] [%s:%d] tip = %d",
00603     __FILE__, __LINE__,
00604     tip);
00605   }
00606 
00607   if (tip == STATIC_IP)
00608   {
00609     add_option_to_profile (options, 3, "IP", mysql_tables->abonne_ip.gateway,
00610                            strlen(mysql_tables->abonne_ip.gateway));
00611     add_option_to_profile (options, 1, "IP", mysql_tables->abonne_ip.subnet,
00612                            strlen(mysql_tables->abonne_ip.subnet));
00613 
00614     if (configuration_globale.debug > 1)
00615     { my_syslog (configuration_globale.log_file,
00616       "[DEBUG] [%s:%d] packets_send_offer: Add gateway and subnet %s %s",
00617       __FILE__, __LINE__,
00618       mysql_tables->abonne_ip.gateway,
00619       mysql_tables->abonne_ip.subnet); }
00620   }
00621 
00622   if (tip == DYNAMIC_IP)
00623   {
00624     add_option_to_profile (options, 3, "IP", mysql_tables->ip_lease.gateway,
00625                            strlen(mysql_tables->ip_lease.gateway));
00626     add_option_to_profile (options, 1, "IP", mysql_tables->ip_lease.subnet,
00627                            strlen(mysql_tables->ip_lease.subnet));
00628     if (configuration_globale.debug > 1)
00629     { my_syslog (configuration_globale.log_file,
00630       "[DEBUG] [%s:%d] packets_send_offer: Add gateway and subnet %s %s",
00631       __FILE__, __LINE__,
00632       mysql_tables->ip_lease.gateway,
00633       mysql_tables->ip_lease.subnet); }
00634   }
00635 
00636   /* ------------------------------------------------------------ */
00637   /* Write packet's options                                       */
00638   /* ------------------------------------------------------------ */
00639 
00640   for (i=1; i<255; i++)
00641   {
00642     if ((options[i]).code != 0)
00643     {
00644        if (configuration_globale.debug > 1)
00645        { my_syslog (configuration_globale.log_file,
00646          "[DEBUG] [%s:%d] packets_send_ack: Adding option %d", __FILE__, __LINE__, i); }
00647        packets_set_option (&packet_out, i, (options[i]).value, (options[i]).len);
00648     }
00649   }
00650 
00651   packets_close_option (&packet_out);
00652 
00653   /* ------------------------------------------------------------ */
00654   /* Send it                                                      */
00655   /* ------------------------------------------------------------ */
00656 
00657   memset ((void*)&addr_target, 0, sizeof(struct sockaddr_in));
00658   adress_size = sizeof (struct sockaddr);
00659 
00660   if (configuration_globale.broadcast_mode == 1)
00661   {
00662      addr_target.sin_family        = AF_INET;
00663      addr_target.sin_port          = htons(TARGET_PORT);
00664      (addr_target.sin_addr).s_addr = broadcast;
00665   }
00666   else
00667   { memcpy ((void*)&addr_target, (void*)client_address, sizeof(struct sockaddr_in)); }
00668 
00669   if (configuration_globale.debug > 0)
00670   { my_syslog (configuration_globale.log_file,
00671     "[DEBUG] [%s:%d] packets_send_ack: Sending DHCP ACK for xid %u",
00672     __FILE__, __LINE__, packets_get_xid(p)); }
00673 
00674 
00675   if (configuration_globale.dumper_mode > 0)
00676   { packet_dump (&packet_out, configuration_globale.debug_file, configuration_globale.csv_file, NULL, &addr_target); }
00677 
00678   #ifndef READ_PACKET_FROM_FILE
00679 
00680   rc = sendto (
00681                 socket_desc,
00682                 (void*)&packet_out,
00683                 packet_out.ctrl.taille,
00684                 0,
00685                 (struct sockaddr*)&addr_target,
00686                 adress_size
00687               );
00688 
00689   if (rc == -1)
00690   {
00691     my_syslog (configuration_globale.log_file, "[WARNING] [%s:%d] Could not send ACK for xid %u - %s",
00692                __FILE__, __LINE__,
00693                packets_get_xid(p),
00694                strerror(errno));
00695     return 1;
00696   }
00697 
00698   #else
00699 
00700     my_syslog (configuration_globale.log_file,
00701                "[INFO] [%s:%d] Reading packet from file => packet no sent (this is normal)",
00702                __FILE__, __LINE__);
00703 
00704   #endif
00705 
00706   return 0;
00707 }
00708 
00709 /*! \brief Log a packet's profile (list of options) in a human readables format.
00710     \author Denis BEURIVE
00711     \param file Pointer to a zero terminated string of characters that represents the path to the log file.
00712     \param mes Pointer to a zero terminated string of characters that represents a text that will be printed
00713            before the profile.
00714     \param profile pointer to a opt data structure that contains the profile to print.
00715     \return Upon successful completion, the function returns the value 0. Othrwise, the function returns the
00716             value 1.
00717  */
00718 
00719 int log_profile (const char *file, const char *mes, const struct opt *profile)
00720 {
00721         int             i, l;
00722         FILE            *fd;
00723         unsigned char   *c;
00724 
00725         fd = fopen (file, "a");
00726         if (fd == NULL) { return 1; }
00727 
00728         fprintf (fd, "%s %s ", dater(), mes);
00729 
00730         for (i=0; i<256; i++)
00731         {
00732           if ((profile[i]).code != 0)
00733           {
00734             fprintf (fd, "(%d) %d [", (profile[i]).code, (profile[i]).len);
00735             c = (unsigned char*)(profile[i]).value;
00736             for (l=0; l<(profile[i]).len; l++)
00737             {
00738               fprintf (fd, "%c%c", int_to_char (((*c) & 0xF0) >> 4), int_to_char ((*c) & 0x0F));
00739               if (l < (profile[i]).len - 1) { fprintf (fd, "."); }
00740               c += 1;
00741             }
00742             fprintf (fd, "]  ");
00743           }
00744         }
00745         fprintf (fd, "\n");
00746 
00747         fclose (fd);
00748         return 0;
00749 }
00750 
00751 
00752 /*! \brief Send a DHCPACK as response to an INFORM.
00753     \author Denis BEURIVE
00754     \param p Pointer to the incoming packet (should be a DHCP INFORM).
00755     \param mysql_tables pointer to a 'mysql_tables' data structure that contains the loaded client's context.
00756     \param broadcast 4 bytes long integer that contains the binary representation (in network byte order)
00757            of the broadcast IP address.
00758     \param server_ip 4 bytes long integer that contains the binary representation (in network byte order)
00759            of the server IP address.
00760     \param socket_desc Socket descriptor of the DHCP server.
00761     \param client_address Pointer to a 'sockaddr_in' data structure that contains the internet address of
00762            the incoming packet's sender.
00763            If the configuration tag 'enable-broadcast-responses' is set to "yes", then the parameter
00764            'client_address' is never used (since the server always send broadcasts).
00765     \return Upon successful completion, the function returns the value 0.
00766             Otherwise, the function returns the value 1.
00767  */
00768 
00769 int reply_to_inform (
00770                       struct dhcp_packet    *p,
00771                       struct mysql_tables   *mysql_tables,
00772                       unsigned long int     broadcast,
00773                       unsigned long int     server_ip,
00774                       int                   socket_desc,
00775                       struct sockaddr_in    *client_address)
00776 {
00777   struct dhcp_packet     packet_out;
00778   struct sockaddr_in     addr_target;
00779   int                    adress_size, rc, i;
00780   char                   *serverip;
00781   struct opt             options[MAX_PROFILE_OPTIONS];
00782 
00783   packets_clear (&packet_out);
00784   serverip = configuration_globale.server_ip_seen_by_client;
00785 
00786   /* ------------------------------------------------------------ */
00787   /* Transfert options from loaded profile (from database) into   */
00788   /* internal profile representation.                             */
00789   /* ------------------------------------------------------------ */
00790 
00791   context2profile (options, mysql_tables);
00792 
00793   /* ------------------------------------------------------------ */
00794   /* Format the ACK                                               */
00795   /* Notes:                                                       */
00796   /* - We don't set  'yiaddr' -> This field will be all zero.     */
00797   /* - We don't set, 'sname' and 'file' are all zero.             */
00798   /* ------------------------------------------------------------ */
00799 
00800   packets_set_op           (&packet_out, BOOTREPLY);
00801   packets_set_htype        (&packet_out, packets_get_htype(p));
00802   packets_set_hlen         (&packet_out, packets_get_hlen(p));
00803   packets_set_hops         (&packet_out, 0);
00804   packets_set_xid          (&packet_out, packets_get_xid(p));
00805   packets_set_secs         (&packet_out, packets_get_secs(p));
00806   packets_set_flags        (&packet_out, packets_get_flags(p));
00807   packets_set_siaddr       (&packet_out, configuration_globale.server_ip_seen_by_client);
00808   packets_set_bin_giaddr   (&packet_out, packets_get_bin_giaddr(p));
00809   packets_set_bin_ciaddr   (&packet_out, packets_get_bin_ciaddr(p));
00810   packets_set_chaddr       (&packet_out, packets_get_bin_chaddr(p));
00811 
00812   /* ------------------------------------------------------------ */
00813   /* Set the correct options' profile                             */
00814   /*    - routers (already in loaded profile)                     */
00815   /*    - domain name (already in loaded profile)                 */
00816   /*    - domain name server (already in loaded profile)          */
00817   /*    - subnet mask (already in loaded profile)                 */
00818   /*    - message type (added)                                    */
00819   /*    - server identifier (added)                               */
00820   /*                                                              */
00821   /* Note: remove lease from option's profile.                    */
00822   /* ------------------------------------------------------------ */
00823 
00824   add_option_to_profile (options, 53, "HEXA-BYTE", DHCPACK_HEXA, strlen(DHCPACK_HEXA)); /* Message type       */
00825   add_option_to_profile (options, 54, "IP",        serverip,     strlen(serverip));     /* Server Identifier  */
00826   
00827   remove_option_from_profile (options, 51);
00828 
00829   /* ------------------------------------------------------------ */
00830   /* Write packet's options                                       */
00831   /* ------------------------------------------------------------ */
00832 
00833   for (i=1; i<255; i++)
00834   {
00835     if ((options[i]).code != 0)
00836     {
00837        packets_set_option (&packet_out, i, (options[i]).value, (options[i]).len);
00838        if (configuration_globale.debug > 1)
00839        { my_syslog (configuration_globale.log_file,
00840          "[DEBUG] [%s:%d] packets_send_ack: Adding option %d", __FILE__, __LINE__, i); }
00841     }
00842   }
00843 
00844   packets_close_option (&packet_out);
00845 
00846   /* ------------------------------------------------------------ */
00847   /* Send it                                                      */
00848   /* ------------------------------------------------------------ */
00849 
00850   adress_size = sizeof (struct sockaddr);
00851   memset ((void*)&addr_target, 0, sizeof(struct sockaddr_in));
00852 
00853   if (configuration_globale.broadcast_mode == 1)
00854   {
00855     addr_target.sin_family        = AF_INET;
00856     addr_target.sin_port          = htons(TARGET_PORT);
00857     (addr_target.sin_addr).s_addr = broadcast;
00858   }
00859   else
00860   { memcpy ((void*)&addr_target, (void*)client_address, sizeof(struct sockaddr_in)); }
00861 
00862   if (configuration_globale.debug > 0)
00863   { my_syslog (configuration_globale.log_file,
00864     "[DEBUG] [%s:%d] packets_send_offer: Sending DHCP OFFER for xid %u",
00865     __FILE__, __LINE__, packets_get_xid(p)); }
00866 
00867   if (configuration_globale.dumper_mode > 0)
00868   { packet_dump (&packet_out, configuration_globale.debug_file, configuration_globale.csv_file, NULL, &addr_target); }
00869 
00870   #ifndef READ_PACKET_FROM_FILE
00871 
00872   rc = sendto (
00873                 socket_desc,
00874                 (void*)&packet_out,
00875                 packet_out.ctrl.taille,
00876                 0,
00877                 (struct sockaddr*)&addr_target,
00878                 adress_size
00879               );
00880 
00881   if (rc == -1)
00882   {
00883     my_syslog (configuration_globale.log_file,
00884                "[WARNING] [%s:%d] Could not send OFFER for xid %u - %s",
00885                __FILE__, __LINE__,
00886                packets_get_xid(p),
00887                strerror(errno));
00888     return 1;
00889   }
00890 
00891   #else
00892 
00893     my_syslog (configuration_globale.log_file,
00894                "[INFO] [%s:%d] Reading packet from file => packet no sent (this is normal)",
00895                __FILE__, __LINE__);
00896 
00897   #endif
00898 
00899   return 0;
00900 }
00901 
00902 /*! \brief Send a DHCPNAK in response to a REQUEST and log the output packet.
00903     \author Denis BEURIVE
00904     \param p Pointer to the incoming packet (should be a DHCP REQUEST).
00905     \param mysql_tables pointer to a 'mysql_tables' data structure that contains the loaded client's
00906            context.
00907     \param ip Pointer to a zero terminated string of characters that represents the client's IP address.
00908     \param broadcast 4 bytes long integer that contains the binary representation (in network byte order) of
00909            the broadcast IP address.
00910     \param server_ip 4 bytes long integer that contains the binary representation (in network byte order) of
00911            the server IP address.
00912     \param socket_desc Socket descriptor of the DHCP server.
00913     \param client_address Pointer to a 'sockaddr_in' data structure that contains the internet address of the
00914            incoming packet's sender.
00915            If the configuration tag 'enable-broadcast-responses' is set to "yes", then the parameter
00916            'client_address' is never used (since the server always sends broadcasts).
00917     \return Upon successful completion, the function returns the value 0.
00918             Otherwise, the function returns the value 1.
00919  */
00920 
00921 int packets_send_nack (
00922                          struct dhcp_packet    *p,
00923                          struct mysql_tables   *mysql_tables,
00924                          char                  *ip,
00925                          unsigned long int     broadcast,
00926                          unsigned long int     server_ip,
00927                          int                   socket_desc,
00928                          struct sockaddr_in    *client_address)
00929 {
00930   struct dhcp_packet     packet_out;
00931   struct sockaddr_in     addr_target;
00932   int                    adress_size, rc, i;
00933   char                   *serverip;
00934   struct opt             options[MAX_PROFILE_OPTIONS];
00935 
00936   packets_clear (&packet_out);
00937   serverip = configuration_globale.server_ip_seen_by_client;
00938 
00939   /* ------------------------------------------------------------ */
00940   /* Initialize the list of options                               */
00941   /* ------------------------------------------------------------ */
00942 
00943   clear_profile(options);
00944 
00945   /* ------------------------------------------------------------ */
00946   /* Format the NAK                                               */
00947   /* ------------------------------------------------------------ */
00948 
00949   packets_set_op           (&packet_out, BOOTREPLY);
00950   packets_set_htype        (&packet_out, packets_get_htype(p));
00951   packets_set_hlen         (&packet_out, packets_get_hlen(p));
00952   packets_set_hops         (&packet_out, 0);
00953   packets_set_xid          (&packet_out, packets_get_xid(p));
00954   packets_set_secs         (&packet_out, packets_get_secs(p));
00955   packets_set_flags        (&packet_out, packets_get_flags(p));
00956   packets_set_yiaddr       (&packet_out, ip);
00957   packets_set_siaddr       (&packet_out, configuration_globale.server_ip_seen_by_client);
00958   packets_set_bin_giaddr   (&packet_out, packets_get_bin_giaddr(p));
00959   packets_set_bin_ciaddr   (&packet_out, packets_get_bin_ciaddr(p));
00960   packets_set_chaddr       (&packet_out, packets_get_bin_chaddr(p));
00961 
00962   /* ------------------------------------------------------------ */
00963   /* Set the type of the response (in this case, a DHCPNAK)       */
00964   /* ------------------------------------------------------------ */
00965 
00966   if (configuration_globale.debug > 1)
00967   { my_syslog (configuration_globale.log_file,
00968                "[DEBUG] [%s:%d] packets_send_nack: Add option 53 (message type) = 6",
00969                __FILE__, __LINE__); }
00970 
00971   add_option_to_profile (options, 53, "HEXA-BYTE", DHCPNAK_HEXA, strlen(DHCPNAK_HEXA)); 
00972 
00973   /* ------------------------------------------------------------ */
00974   /* Set the IP address of the DHCP server (for futur requests)   */
00975   /* ------------------------------------------------------------ */
00976 
00977   if (configuration_globale.debug > 1)
00978   { my_syslog (configuration_globale.log_file,
00979                "[DEBUG] [%s:%d] packets_send_nack: Add option 54 (server ID) %s",
00980                __FILE__, __LINE__, serverip); }
00981 
00982   add_option_to_profile (options, 54, "IP", serverip, strlen(serverip)); 
00983 
00984   /* ------------------------------------------------------------ */
00985   /* Write packet's options                                       */
00986   /* ------------------------------------------------------------ */
00987 
00988   for (i=1; i<255; i++)
00989   {
00990     if ((options[i]).code != 0)
00991     {
00992        if (configuration_globale.debug > 1)
00993        { my_syslog (configuration_globale.log_file,
00994          "[DEBUG] [%s:%d] packets_send_nack: Adding option %d", __FILE__, __LINE__, i); }
00995        packets_set_option (&packet_out, i, (options[i]).value, (options[i]).len);
00996     }
00997   }
00998 
00999   /* ------------------------------------------------------------ */
01000   /* Send it                                                      */
01001   /* ------------------------------------------------------------ */
01002 
01003   packets_close_option (&packet_out);
01004 
01005   memset ((void*)&addr_target, 0, sizeof(struct sockaddr_in));
01006   adress_size = sizeof (struct sockaddr);
01007 
01008   if (configuration_globale.broadcast_mode == 1)
01009   {
01010      addr_target.sin_family        = AF_INET;
01011      addr_target.sin_port          = htons(TARGET_PORT);
01012      (addr_target.sin_addr).s_addr = broadcast;
01013   }
01014   else
01015   { memcpy ((void*)&addr_target, (void*)client_address, sizeof(struct sockaddr_in)); }
01016 
01017   if (configuration_globale.debug > 0)
01018   { my_syslog (configuration_globale.log_file,
01019     "[DEBUG] [%s:%d] packets_send_nack: Sending DHCP NACK for xid %u",
01020     __FILE__, __LINE__, packets_get_xid(p)); }
01021 
01022   if (configuration_globale.dumper_mode > 0)
01023   { packet_dump (&packet_out, configuration_globale.debug_file, configuration_globale.csv_file, NULL, &addr_target); }
01024 
01025   #ifndef READ_PACKET_FROM_FILE
01026 
01027     /* ---------------------------------------------------------- */
01028     /* This is not a simulation, send the response                */
01029     /* ---------------------------------------------------------- */
01030 
01031     rc = sendto (
01032                   socket_desc,
01033                   (void*)&packet_out,
01034                   packet_out.ctrl.taille,
01035                   0,
01036                   (struct sockaddr*)&addr_target,
01037                   adress_size
01038                 );
01039   
01040     if (rc == -1)
01041     {
01042       my_syslog (configuration_globale.log_file,
01043                  "[WARNING] [%s:%d] Could not send NAK for xid %u - %s",
01044                  __FILE__, __LINE__,
01045                  packets_get_xid(p),
01046                  strerror(errno));
01047       return 1;
01048     }
01049 
01050   #else
01051 
01052     /* ---------------------------------------------------------- */
01053     /* This is a simulation, do not send any response             */
01054     /* ---------------------------------------------------------- */
01055 
01056     my_syslog (configuration_globale.log_file,
01057                "[INFO] [%s:%d] Reading packet from file => packet (NAK) not sent (simulation)",
01058                __FILE__, __LINE__);
01059 
01060   #endif
01061 
01062   return 0;
01063 }
01064 
01065 /*! \brief Send a dummy DHCPNAK and log the output packet.
01066     \author Denis BEURIVE
01067     \param p Pointer to the incoming packet (should be a DHCP REQUEST).
01068     \param mysql_tables pointer to a 'mysql_tables' data structure that contains the loaded client's
01069            context.
01070     \param ip Pointer to a zero terminated string of characters that represents the client's IP address.
01071     \param broadcast 4 bytes long integer that contains the binary representation (in network byte order) of
01072            the broadcast IP address.
01073     \param server_ip 4 bytes long integer that contains the binary representation (in network byte order) of
01074            the server IP address.
01075     \param socket_desc Socket descriptor of the DHCP server.
01076     \param client_address Pointer to a 'sockaddr_in' data structure that contains the internet address of the
01077            incoming packet's sender.
01078            If the configuration tag 'enable-broadcast-responses' is set to "yes", then the parameter
01079            'client_address' is never used (since the server always sends broadcasts).
01080     \return Upon successful completion, the function returns the value 0.
01081             Otherwise, the function returns the value 1.
01082  */
01083 
01084 int packets_send_dummy_nak (
01085                              struct dhcp_packet    *p,
01086                              struct mysql_tables   *mysql_tables,
01087                              char                  *ip,
01088                              unsigned long int     broadcast,
01089                              unsigned long int     server_ip,
01090                              int                   socket_desc,
01091                              struct sockaddr_in    *client_address)
01092 {
01093   int cr;
01094 
01095   my_syslog (configuration_globale.log_file,
01096              "[DUMMY RESPONSE] [%s:%d] packets_send_dummy_nak: Sending DUMMY DHCPNAK",
01097              __FILE__, __LINE__);
01098 
01099   cr = packets_send_nack ( p,
01100                            mysql_tables,
01101                            ip,
01102                            broadcast,
01103                            server_ip,
01104                            socket_desc,
01105                            client_address);
01106 
01107   if (cr == 1)
01108   {
01109     my_syslog (configuration_globale.log_file,
01110                "[ERROR] [%s:%d] packets_send_dummy_nak: Could not send the DUMMY DHCPNAK",
01111                __FILE__, __LINE__);
01112     return 1;
01113   }
01114 
01115   return 0;
01116 }
01117 
01118 
01119 
01120 
01121 
01122 
01123 

Generated on Mon Jun 19 12:31:06 2006 for MyDhcp_V2 by doxygen1.2.15