nis-util  1.0.D108
lib/space/netmasks.cc
Go to the documentation of this file.
00001 //
00002 // nis-util - NIS Administration Utilities
00003 // Copyright (C) 2002, 2008, 2009, 2011, 2012 Peter Miller
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or (at
00008 // your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program. If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <lib/ac/string.h>
00020 #include <arpa/inet.h>
00021 #include <lib/ac/ctype.h>
00022 #include <netinet/in.h>
00023 
00024 #include <lib/net_utils.h>
00025 #include <lib/space/netmasks.h>
00026 
00027 
00028 space_netmasks::~space_netmasks()
00029 {
00030 }
00031 
00032 
00033 space_netmasks::space_netmasks(const rcstring &a_filename) :
00034     space(a_filename),
00035     last_number(0)
00036 {
00037     discard_comments();
00038     discard_blank_lines();
00039 }
00040 
00041 
00042 space_netmasks::pointer
00043 space_netmasks::create(const rcstring &a_filename)
00044 {
00045     return pointer(new space_netmasks(a_filename));
00046 }
00047 
00048 
00049 space_netmasks::record::pointer
00050 space_netmasks::get(void)
00051 {
00052     for (;;)
00053     {
00054         source_location line_locn;
00055         line_t line;
00056         if (!read_one_line(line_locn, line))
00057         {
00058             last_number = 0;
00059             return record::pointer();
00060         }
00061         if (line.size() < 2)
00062         {
00063             error
00064             (
00065                 line_locn,
00066                 "too few fields (expected 2, given %ld)",
00067                 (long)line.size()
00068             );
00069             continue;
00070         }
00071         if (line.size() > 2)
00072         {
00073             error
00074             (
00075                 line_locn,
00076                 "too many fields (expected 2, given %ld)",
00077                 (long)line.size()
00078             );
00079         }
00080 
00081         //
00082         // Check the network number.
00083         //
00084         in_addr tmp_addr;
00085         if (!inet_aton(line[0].c_str(), &tmp_addr))
00086         {
00087             error
00088             (
00089                 line_locn,
00090                 "network number %s not valid",
00091                 line[0].quote_c().c_str()
00092             );
00093             continue;
00094         }
00095         rcstring temp(inet_ntoa(tmp_addr));
00096         if (temp != line[0])
00097         {
00098             error
00099             (
00100                 line_locn,
00101                 "network number %s not in correct format, use %s instead",
00102                 line[0].quote_c().c_str(),
00103                 temp.quote_c().c_str()
00104             );
00105         }
00106         rcstring rec_number = temp;
00107         unsigned long rec_number_binary = ntohl(tmp_addr.s_addr);
00108 
00109         //
00110         // Check record ordering
00111         //
00112         if (last_number > rec_number_binary)
00113         {
00114             error
00115             (
00116                 line_locn,
00117                 "network %s out of order",
00118                 rec_number.quote_c().c_str()
00119             );
00120             explain_sequence_errors();
00121         }
00122         last_number = rec_number_binary;
00123 
00124         //
00125         // Check that it is class A, B or C.
00126         // Any other class is invalid.
00127         //
00128         int net_class = network_class_from_number(rec_number_binary);
00129         if (net_class > 'C')
00130         {
00131             error(line_locn, "networks of class %c are reserved", net_class);
00132         }
00133 
00134         //
00135         // Check the network mask.
00136         //
00137         rcstring rec_mask = line[1];
00138         if (!inet_aton(rec_mask.c_str(), &tmp_addr))
00139         {
00140             error
00141             (
00142                 line_locn,
00143                 "network mask %s not valid",
00144                 rec_mask.quote_c().c_str()
00145             );
00146             continue;
00147         }
00148         temp = rcstring(inet_ntoa(tmp_addr));
00149         if (temp != rec_mask)
00150         {
00151             error
00152             (
00153                 line_locn,
00154                 "network mask %s not in correct format, use %s instead",
00155                 rec_mask.quote_c().c_str(),
00156                 temp.quote_c().c_str()
00157             );
00158             rec_mask = temp;
00159         }
00160         unsigned long rec_mask_binary = ntohl(tmp_addr.s_addr);
00161 
00162         //
00163         // Make sure the network mask has the correct pattern of ones
00164         // and zeros.  Otherwise it's stuffed.
00165         //
00166         {
00167             unsigned long tmp_mask = rec_mask_binary;
00168             unsigned long vfy_mask = 0xFFFFFFFFuL ^ (LSB(tmp_mask) - 1);
00169             vfy_mask &= ~3; // smallest possible subnet
00170             if (vfy_mask != tmp_mask)
00171             {
00172                 rcstring s = string_from_network_number(vfy_mask);
00173                 error
00174                 (
00175                     line_locn,
00176                     "network mask %s not valid, "
00177                         "suggest network mask %s instead",
00178                     rec_mask.quote_c().c_str(),
00179                     s.quote_c().c_str()
00180                 );
00181 
00182                 // to avoid cascading errors, re-write the rule
00183                 rec_mask_binary = vfy_mask;
00184                 rec_mask = s;
00185             }
00186         }
00187 
00188         //
00189         // Make sure there are at least 2 bits at the bottom, otherwise
00190         // there are insufficient bits for hosts.
00191         //
00192         if (rec_number_binary & 3)
00193         {
00194             unsigned long tmp_number = rec_number_binary & ~3;
00195             rcstring tmp_number_str = string_from_network_number(tmp_number);
00196             error
00197             (
00198                 line_locn,
00199                 "network number %s has no room for any hosts, "
00200                     "suggest network number %s instead",
00201                 rec_number.quote_c().c_str(),
00202                 tmp_number_str.quote_c().c_str()
00203             );
00204 
00205             // to avoid cascading errors, re-write the rule
00206             rec_number_binary = tmp_number;
00207             rec_number = tmp_number_str;
00208         }
00209         if (rec_mask_binary & 3)
00210         {
00211             unsigned long tmp_mask = rec_mask_binary & ~3;
00212             rcstring s = string_from_network_number(tmp_mask);
00213             error
00214             (
00215                 line_locn,
00216                 "network mask %s has no room for any hosts, "
00217                     "suggest network mask %s instead",
00218                 rec_mask.quote_c().c_str(),
00219                 s.quote_c().c_str()
00220             );
00221 
00222             // to avoid cascading errors, re-write the rule
00223             rec_mask_binary = tmp_mask;
00224             rec_mask = s;
00225         }
00226 
00227         //
00228         // Sanity check the network number against the inverse
00229         // of the network mask.  We know the mask is valid at this point.
00230         //
00231         if (rec_number_binary & ~rec_mask_binary)
00232         {
00233             unsigned long vfy_num = rec_number_binary & rec_mask_binary;
00234             rcstring vfy_num_str = string_from_network_number(vfy_num);
00235             unsigned long vfy_mask =
00236                 0xFFFFFFFFuL ^ (LSB(rec_number_binary) - 1);
00237             rcstring vfy_mask_str = string_from_network_number(vfy_mask);
00238 
00239             if (vfy_num != rec_number_binary)
00240             {
00241                 if (vfy_mask != rec_mask_binary)
00242                 {
00243                     error
00244                     (
00245                         line_locn,
00246                         "network number %s and network mask %s "
00247                             "inconsistent, suggest network number %s "
00248                             "or network mask %s instead",
00249                         rec_number.quote_c().c_str(),
00250                         rec_mask.quote_c().c_str(),
00251                         vfy_num_str.quote_c().c_str(),
00252                         vfy_mask_str.quote_c().c_str()
00253                     );
00254                     // to avoid cascading errors, re-write the rule
00255                     rec_mask_binary = vfy_mask;
00256                     rec_mask = vfy_mask_str;
00257                 }
00258                 else
00259                 {
00260                     error
00261                     (
00262                         line_locn,
00263                         "network number %s and network mask %s inconsistent, "
00264                             "suggest network number %s instead",
00265                         rec_number.quote_c().c_str(),
00266                         rec_mask.quote_c().c_str(),
00267                         vfy_num_str.quote_c().c_str()
00268                     );
00269                     // to avoid cascading errors, re-write the rule
00270                     rec_number_binary = vfy_num;
00271                     rec_number = vfy_num_str;
00272                 }
00273             }
00274             else
00275             {
00276                 error
00277                 (
00278                     line_locn,
00279                     "network number %s and network mask %s inconsistent, "
00280                         "suggest network mask %s instead",
00281                     rec_number.quote_c().c_str(),
00282                     rec_mask.quote_c().c_str(),
00283                     vfy_mask_str.quote_c().c_str()
00284                 );
00285                 // to avoid cascading errors, re-write the rule
00286                 rec_mask_binary = vfy_mask;
00287                 rec_mask = vfy_mask_str;
00288             }
00289         }
00290 
00291         //
00292         // build the new record and pass it to the caller.
00293         //
00294         return record::create(line_locn, rec_number, rec_mask);
00295     }
00296 }
00297 
00298 
00299 space_netmasks::record::~record()
00300 {
00301 }
00302 
00303 
00304 space_netmasks::record::record(
00305     const source_location &a_locn,
00306     const rcstring &a_number,
00307     const rcstring &a_mask
00308 ) :
00309     locn(a_locn),
00310     number(a_number),
00311     mask(a_mask)
00312 {
00313 }
00314 
00315 
00316 space_netmasks::record::pointer
00317 space_netmasks::record::create(const source_location &a_locn,
00318     const rcstring &a_number, const rcstring &a_mask)
00319 {
00320     return pointer(new record(a_locn, a_number, a_mask));
00321 }
00322 
00323 
00324 unsigned long
00325 space_netmasks::record::get_number_binary(void)
00326     const
00327 {
00328     return network_number_from_string(number);
00329 }
00330 
00331 
00332 unsigned long
00333 space_netmasks::record::get_mask_binary(void)
00334     const
00335 {
00336     return network_number_from_string(mask);
00337 }
00338 
00339 
00340 rcstring
00341 space_netmasks::record::representation(void)
00342     const
00343 {
00344     return (number + " " + mask);
00345 }
00346 
00347 
00348 // vim: set ts=8 sw=4 et :