1---------------------------------------------------------------- 2-- IRONSIDES - DNS SERVER 3-- 4-- By: Martin C. Carlisle and Barry S. Fagin 5-- Department of Computer Science 6-- United States Air Force Academy 7-- 8-- This is free software; you can redistribute it and/or 9-- modify without restriction. We do ask that you please keep 10-- the original author information, and clearly indicate if the 11-- software has been modified. 12-- 13-- This software is distributed in the hope that it will be useful, 14-- but WITHOUT ANY WARRANTY; without even the implied warranty 15-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16---------------------------------------------------------------- 17 18WITH Dns_Table_Pkg, zone_file_parser, error_msgs; 19with parser_utilities, Rr_Type.A_Record_Type, Rr_Type.Aaaa_Record_Type, Rr_Type.Cname_Record_Type, 20 Rr_Type.Mx_Record_Type, RR_Type.srv_record_type, Rr_Type.Ns_Record_Type, Rr_Type.Nsec_Record_Type, Rr_Type.Ptr_Record_Type; 21 22--just in case debugging needed 23--WITH Ada.Text_IO, Ada.Integer_Text_IO; 24 25package body process_first_line_of_record is 26--had to encapsulate this in a separate procedure to help the examiner 27--lots of parameters because of line-oriented file processing, different 28--kinds of parameters and multiline records require large amount of state 29--to persist across procedure calls 30 procedure ProcessFirstLineOfRecord (CurrentRecordType : in Dns_Types.Query_Type; 31 --common to all record types 32 currentOrigin : in Rr_Type.DomainNameStringType; 33 currentOwner : in Rr_Type.DomainNameStringType; 34 currentTTL : in unsigned_types.Unsigned32; 35 currentClass : in Rr_Type.ClassType; 36 currentLine : in rr_type.LineFromFileType; 37 Lastpos : in Rr_Type.Linelengthindex; 38 LineCount : Unsigned_Types.Unsigned32; 39 --for multiline records 40 InMultilineRecord : out Boolean; 41 LineInRecordCtr : out Unsigned_Types.Unsigned32; 42 --SOA record fields 43 currentNameServer : out rr_Type.DomainNameStringType; 44 CurrentEmail : out Rr_Type.DomainNameStringType; 45 --DNSKEY record (if needed) 46 DNSKEY_Rec : out Rr_Type.Dnskey_Record_Type.DNSKeyRecordType; 47 --RRSIG record (if needed) 48 RRSIG_Rec : out Rr_Type.rrsig_record_type.RRSIGRecordType; 49 recordSuccessfullyInserted : out Boolean; 50 Success : in out boolean) 51 is 52 currentIpv4 : Unsigned_Types.Unsigned32; 53 currentIpv6 : rr_type.aaaa_record_type.IPV6AddrType; 54 currentDomainName : rr_type.DomainNameStringType; 55 CurrentPref : Unsigned_Types.Unsigned16; 56 CurrentWeight : Unsigned_Types.Unsigned16; 57 CurrentPort : Unsigned_Types.Unsigned16; 58 RRString : Rr_Type.LineFromFileType; 59 NumberOfBlocks: rr_type.nsec_record_type.blockNumberValue; 60 NumberOfRecordTypes: Rr_Type.Nsec_Record_Type.RecordTypeIndexValue; 61 recordTypes : rr_type.nsec_record_type.recordTypeArrayType; 62 BlockNumbers: Rr_Type.Nsec_Record_Type.BlockNumberArrayType; 63 BlockLengths: Rr_Type.Nsec_Record_Type.BlockLengthArrayType; 64 bitMaps: Rr_Type.Nsec_Record_Type.BitMapsArrayArrayType; 65 begin 66 --these assignments all make bogus flow errors go away 67 inMultilineRecord := false; 68 lineInRecordCtr := 0; 69 currentNameServer := rr_type.BlankDomainName; 70 CurrentEmail := Rr_Type.BlankDomainName; 71 DNSKEY_Rec := Rr_Type.Dnskey_Record_Type.BlankDNSKeyRecord; 72 RRSIG_Rec := rr_type.rrsig_record_type.blankRRSIGRecord; 73 RecordSuccessfullyInserted := True; 74 75 CASE CurrentRecordType IS 76 WHEN Dns_Types.A => --A records 77 --next data item must be an ipv4 addr 78 Zone_File_Parser.ParseIpv4(currentIpv4, CurrentLine, LastPos, Success); 79 80 --can now build and insert a complete A record 81 if Success then 82 Dns_Table_Pkg.DNS_Table.InsertARecord( 83 Rr_Type.ConvertDomainNameToWire(CurrentOwner), 84 rr_type.a_record_type.ARecordType'( 85 TtlInSeconds => CurrentTTL, Class => CurrentClass, 86 Ipv4 => CurrentIpv4), RecordSuccessfullyInserted); 87 end if; 88 89 when Dns_Types.AAAA => --AAAA records 90 --next item must be an ipv6 address 91 Zone_File_Parser.ParseIpv6(currentIpv6, CurrentLine, LastPos, Success); 92 93 --can now build and insert a complete AAAA record 94 if Success then 95 dns_Table_Pkg.DNS_Table.InsertAAAARecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 96 Rr_Type.Aaaa_Record_Type.AaaaRecordType'( 97 TtlInSeconds => CurrentTTL, Class => CurrentClass, 98 ipv6 => currentIpv6), recordSuccessfullyInserted); 99 end if; 100 101 when Dns_Types.CNAME => --CNAME records 102 --next item must be a domain name 103 Zone_File_Parser.ParseDomainName(currentDomainName, CurrentLine, LastPos, Success); 104 105 if success then 106 --if domain name does not end in '.', append value of $ORIGIN 107 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 108 LastPos, LineCount, Success); 109 end if; 110 111 --can now build and insert a complete CNAME record 112 if success then 113 dns_table_pkg.DNS_Table.insertCNAMERecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 114 rr_type.cname_record_type.CNAMERecordType'( 115 ttlInSeconds => currentTTL , class => currentClass, 116 CanonicalDomainName => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 117 RecordSuccessfullyInserted); 118 end if; 119 120 when dns_types.MX => --MX records 121 --next must come a preference value, then a domain name (mail exchanger) 122 zone_file_parser.parsePrefAndDomainName(currentPref, currentDomainName, 123 CurrentLine, LastPos, Success); 124 if success then 125 --if domain name does not end in '.', append value of $ORIGIN 126 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 127 LastPos, LineCount, Success); 128 end if; 129 130 if success then 131 --can now build and insert a complete MX record 132 dns_table_pkg.DNS_Table.insertMXRecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 133 rr_type.mx_record_type.MXRecordType'( 134 ttlInSeconds => currentTTL , class => currentClass, 135 Pref => CurrentPref, 136 MailExchanger => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 137 RecordSuccessfullyInserted); 138 end if; 139 140 when dns_types.SRV => --SRV records 141 --next must come preference value, weight, port, then a domain name (server name) 142 zone_file_parser.parsePrefWeightPortAndDomainName(currentPref, currentWeight, currentPort, currentDomainName, 143 CurrentLine, LastPos, Success); 144 if success then 145 --if domain name does not end in '.', append value of $ORIGIN 146 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 147 LastPos, LineCount, Success); 148 end if; 149 150 if success then 151 --can now build and insert a complete SRV record 152 dns_table_pkg.DNS_Table.insertSRVRecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 153 rr_type.srv_record_type.SRVRecordType'( 154 ttlInSeconds => currentTTL , 155 class => currentClass, 156 Pref => CurrentPref, 157 Weight => CurrentWeight, 158 PortNum => CurrentPort, 159 ServerName => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 160 RecordSuccessfullyInserted); 161 end if; 162 163 WHEN Dns_Types.NS => --NS records 164 --next item must be a valid host name 165 Zone_File_Parser.ParseDomainName(CurrentDomainName, CurrentLine, LastPos, Success); 166 parser_utilities.checkValidHostName(currentDomainName, Success); 167 if success then 168 --if domain name does not end in '.', append value of $ORIGIN 169 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 170 LastPos, LineCount, Success); 171 end if; 172 173 if success then 174 --can now build and insert a complete NS record 175 dns_table_pkg.DNS_Table.insertNSRecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 176 rr_type.ns_record_type.NSRecordType'( 177 ttlInSeconds => currentTTL , class => currentClass, 178 NameServer => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 179 RecordSuccessfullyInserted); 180 end if; 181 182 when Dns_Types.PTR => --PTR records 183 Zone_File_Parser.ParseDomainName(CurrentDomainName, CurrentLine, LastPos, Success); 184 if success then 185 --if domain name does not end in '.', append value of $ORIGIN 186 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 187 lastPos, lineCount, Success); 188 end if; 189 190 if success then 191 --can now build and insert a complete PTR record 192 dns_table_pkg.DNS_Table.insertPTRRecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 193 rr_type.ptr_record_type.PTRRecordType'( 194 ttlInSeconds => currentTTL , class => currentClass, 195 DomainName => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 196 RecordSuccessfullyInserted); 197 end if; 198 199 when Dns_Types.SOA => --SOA records 200 InMultilineRecord := True; 201 lineInRecordCtr := 0; 202 Zone_File_Parser.ParseNameServerAndEmail(CurrentNameServer, CurrentEmail, 203 CurrentLine, LastPos, Success); 204 --complete SOA record is inserted later, after all the other fields parsed 205 206 --if name server or email do not end in '.', append value of $ORIGIN 207 if success then 208 parser_utilities.CheckAndAppendOrigin(CurrentNameServer, CurrentOrigin, CurrentLine, 209 LastPos, LineCount, Success); 210 end if; 211 212 --if name server or email do not end in '.', append value of $ORIGIN 213 if success then 214 parser_utilities.CheckAndAppendOrigin(CurrentEmail, CurrentOrigin, CurrentLine, 215 LastPos, LineCount, Success); 216 end if; 217 218 parser_utilities.CheckValidHostName(CurrentNameServer, Success); 219 --NOTE: CurrentEmail should eventually be checked too, but under slightly 220 --different rules, see pg 77 of 4th edition O'Reilly BIND book 221 222 --DNSSEC records below 223 when Dns_Types.DNSKEY => --DNSKEY records 224 InMultilineRecord := True; 225 lineInRecordCtr := 0; 226 Zone_File_Parser.ParseDNSKeyHeader(DNSKEY_Rec, CurrentLine, LastPos, Success); 227 --complete DNSKEY record will be inserted later, after key field parsed 228 229 when Dns_Types.NSEC => 230 Zone_File_Parser.ParseDomainNameAndRRString( 231 CurrentDomainName, RRString, CurrentLine, LastPos, Success); 232 parser_utilities.checkValidHostName(currentDomainName, Success); 233 if success then 234 --if domain name does not end in '.', append value of $ORIGIN 235 parser_utilities.CheckAndAppendOrigin(CurrentDomainName, CurrentOrigin, CurrentLine, 236 LastPos, LineCount, Success); 237 END IF; 238 Zone_File_Parser.FillBlockInfo(RRString, NumberOfRecordTypes, RecordTypes, NumberOfBlocks, BlockNumbers, 239 blockLengths, bitMaps, LineCount, Success); 240 if success then 241 --can now build and insert a complete NSEC record 242 dns_table_pkg.DNS_Table.insertNSECRecord(Rr_Type.ConvertDomainNameToWire(CurrentOwner), 243 rr_type.nsec_record_type.NSECRecordType'( 244 TtlInSeconds => CurrentTTL, Class => CurrentClass, RecordList => RRString, 245 numberOfRecordTypes => numberOfRecordTypes, recordTypes => recordTypes, 246 numberOfBlocks => numberofBlocks, blockNumbers => blockNumbers, blockLengths => blockLengths, bitMaps => bitMaps, 247 NextDomainName => Rr_Type.ConvertDomainNameToWire(CurrentDomainName)), 248 RecordSuccessfullyInserted); 249 else --must have been missing a record type 250 error_msgs.printMissingRecordTypeErrorInfo(currentLine, lastPos, lineCount); 251 end if; 252 253 when Dns_Types.RRSIG => 254 InMultilineRecord := True; 255 LineInRecordCtr := 0; 256 Zone_File_Parser.ParseRRSigHeader(RRSIG_Rec, CurrentLine, LastPos, Success); 257 258 when others => -- can add more supported types here if needed 259 error_msgs.printUnsupportedRecordWarning(currentLine, lastPos, lineCount); 260 END CASE; 261 end ProcessFirstLineOfRecord; 262end process_first_line_of_record; 263