<> <> <> <> DIRECTORY Ascii USING [Digit], BasicTime USING [GetClockPulses, GMT, Now, Pulses, Period, PulsesToMicroseconds, Update], IO USING [Backup, EndOfStream, GetChar, PutFR, RIS, STREAM, Value], Rope USING [Concat, Equal, Fetch, Find, Length, ROPE, Substr], RopeList USING [EqualLists], IPConfig USING [specialDomains, rootServers, rootServerAddresses], IPDefs USING [Byte, DataBuffer, Datagram, DatagramRec, DByte, Address, InternetHeader, nullAddress], IPName, IPNameCache, IPNameSupport USING [AddressInList, MakeAddressInList, MakeRopeInList, LogRope, AliasSummaryLine, AddressSummaryLine, NameSummaryLine, ZoneSummaryLine, MXSummaryLine], IPNameUdp USING [AppendQuery, Class, DomainHeader, EndOfData, GetIPAddress, GetTtl, GetCardinal, GetTwoBytes, GetName, Type], IPRouter USING [BestAddress, SortAddresses], UDP USING [BodyRec, Create, default, Destroy, domain, Handle, minLength, Receive, Send]; IPNameImpl: CEDAR MONITOR IMPORTS Ascii, BasicTime, IO, Rope, RopeList, IPConfig, IPNameCache, IPNameSupport, IPNameUdp, IPRouter, UDP EXPORTS IPName = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; sequenceNumber: CARDINAL _ 0; <<-- Default Time To Lives (end in 777 so it's obvious where these come from)>> ttlDefault: INT = 3777; mxTTL: INT = 77777; bogusTTL: INT = 77777; downTTL: INT = 1777; -- Less than half hour (less than time for sick host retry) AliasEntry: TYPE = IPNameCache.AliasEntry; NameEntry: TYPE = IPNameCache.NameEntry; MXEntry: TYPE = IPNameCache.MXEntry; BogusNameEntry: TYPE = IPNameCache.BogusNameEntry; DownNameEntry: TYPE = IPNameCache.DownNameEntry; AddressEntry: TYPE = IPNameCache.AddressEntry; BogusAddressEntry: TYPE = IPNameCache.BogusAddressEntry; DownAddressEntry: TYPE = IPNameCache.DownAddressEntry; ZoneEntry: TYPE = IPNameCache.ZoneEntry; rootServerAddresses: LIST OF IPDefs.Address _ IPConfig.rootServerAddresses; rootServers: LIST OF Rope.ROPE _ IPConfig.rootServers; LoadCacheFromName: PUBLIC PROC [name: Rope.ROPE, takeOld, needAddress: BOOL _ FALSE] RETURNS [state: IPName.NameState] = { <> <> entry, initEntry: NameEntry; alias, bogus, down, mx, aliasmx, gotAddress: BOOL _ FALSE; IF Rope.Length[name] > 0 AND Rope.Fetch[name, 0] = '[ THEN RETURN[nameOk]; IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".ARPA"]; [initEntry, bogus, down, mx, alias] _ FetchNameEntry[name, takeOld]; IF bogus THEN RETURN[bogus]; IF ~needAddress THEN { SELECT TRUE FROM alias => RETURN[aliasOk]; mx => RETURN[mxOk]; initEntry # NIL => { initEntry.nameCacheLoad _ initEntry.nameCacheLoad.SUCC; RETURN[nameOk]}; ENDCASE; } ELSE { SELECT TRUE FROM alias => { aliasEntry: AliasEntry _ IPNameCache.AliasLookup[name]; [entry, bogus, down, aliasmx, alias] _ FetchNameEntry[aliasEntry.name, takeOld]; IF bogus THEN RETURN[bogus]; IF down THEN RETURN[down]; IF entry # NIL THEN { entry.nameCacheLoad _ entry.nameCacheLoad.SUCC; gotAddress _ TRUE}; IF aliasmx THEN { mxEntry: MXEntry _ IPNameCache.MXLookup[aliasEntry.name]; FOR list: LIST OF IPNameCache.MXHostInfo _ mxEntry.mxHosts, list.rest UNTIL list = NIL DO mxName: Rope.ROPE _ list.first.host; [entry, bogus, down, aliasmx, alias] _ FetchNameEntry[mxName, takeOld]; IF entry # NIL THEN { entry.nameCacheLoad _ entry.nameCacheLoad.SUCC; gotAddress _ TRUE }; ENDLOOP; }; IF gotAddress THEN RETURN[aliasOk]; }; mx => { mxEntry: MXEntry _ IPNameCache.MXLookup[name]; FOR list: LIST OF IPNameCache.MXHostInfo _ mxEntry.mxHosts, list.rest UNTIL list = NIL DO mxName: Rope.ROPE _ list.first.host; [entry, bogus, down, mx, alias] _ FetchNameEntry[mxName, takeOld]; IF entry # NIL THEN { entry.nameCacheLoad _ entry.nameCacheLoad.SUCC; gotAddress _ TRUE }; ENDLOOP; IF gotAddress THEN RETURN[mxOk]; }; initEntry # NIL => { initEntry.nameCacheLoad _ initEntry.nameCacheLoad.SUCC; RETURN[nameOk]}; ENDCASE; }; RETURN[down]; }; <> NameToAddress: PUBLIC PROC [name: Rope.ROPE, mail: BOOL _ FALSE] RETURNS [addresses: LIST OF IPDefs.Address_ NIL] = { entry, mxEntry: NameEntry _ NIL; bogus: BOOL _ FALSE; alias, down, mx, aliasmx: BOOL; length: INT _ Rope.Length[name]; IF length > 2 AND Rope.Fetch[name, 0] = '[ THEN { -- It's an address already address: IPDefs.Address; IF Tailed[name, ".ARPA"] THEN name _ StripTail[name, ".ARPA"]; address _ ParseAddress[IO.RIS[name] !AddressError => {bogus _ TRUE; CONTINUE};]; IF bogus THEN RETURN[NIL] ELSE RETURN [LIST[address]]; }; IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".ARPA"]; [entry, bogus, down, mx, alias] _ FetchNameEntry[name, FALSE]; IF bogus THEN RETURN[NIL]; IF entry # NIL AND ~mail THEN { addresses _ AppendAddressList[addresses, entry.addresses]; entry.nameToAddress _ entry.nameToAddress.SUCC; RETURN[addresses]; }; IF alias THEN { aliasEntry: AliasEntry _ IPNameCache.AliasLookup[name]; [entry, , , aliasmx, ] _ FetchNameEntry[aliasEntry.name, FALSE]; IF entry # NIL AND ~mail THEN { addresses _ AppendAddressList[addresses, entry.addresses]; entry.nameToAddress _ entry.nameToAddress.SUCC; RETURN[addresses]; }; IF aliasmx AND mail THEN { mxHosts: LIST OF Rope.ROPE _ NameToMXHostList[aliasEntry.name]; FOR list: LIST OF Rope.ROPE _ mxHosts, list.rest UNTIL list = NIL DO mxName: Rope.ROPE _ list.first; [mxEntry, , , , ] _ FetchNameEntry[mxName, FALSE]; IF mxEntry # NIL THEN { addresses _ AppendAddressList[addresses, mxEntry.addresses]; mxEntry.nameToAddress _ mxEntry.nameToAddress.SUCC; }; ENDLOOP; }; }; IF mx AND mail THEN { mxHosts: LIST OF Rope.ROPE _ NameToMXHostList[name]; FOR list: LIST OF Rope.ROPE _ mxHosts, list.rest UNTIL list = NIL DO mxName: Rope.ROPE _ list.first; [mxEntry, , , , ] _ FetchNameEntry[mxName, FALSE]; IF mxEntry # NIL THEN { addresses _ AppendAddressList[addresses, mxEntry.addresses]; mxEntry.nameToAddress _ mxEntry.nameToAddress.SUCC; }; ENDLOOP; }; IF entry # NIL THEN { addresses _ AppendAddressList[addresses, entry.addresses]; entry.nameToAddress _ entry.nameToAddress.SUCC; }; RETURN[addresses]; }; AppendAddressList: PROC [oldList: LIST OF IPDefs.Address, addList: LIST OF IPDefs.Address] RETURNS[newList: LIST OF IPDefs.Address] = { orderedAddList: LIST OF IPDefs.Address _ IPRouter.SortAddresses[addList]; -- best address first newList _ oldList; FOR list: LIST OF IPDefs.Address _ orderedAddList, list.rest UNTIL list = NIL DO address: IPDefs.Address _ list.first; newList _ IPNameSupport.MakeAddressInList[newList, address]; ENDLOOP; }; <> NameToMXHostList: PUBLIC PROC [name: Rope.ROPE] RETURNS [hosts: LIST OF Rope.ROPE] = { entry: MXEntry; entry _ IPNameCache.MXLookup[name]; IF entry = NIL THEN RETURN[NIL]; RETURN[SortMXHosts[entry]]; }; <> SortMXHosts: PROC [entry: MXEntry] RETURNS [sorted: LIST OF Rope.ROPE _ NIL] = { bestPreference: INT _ INT.LAST; -- least is best prevBestPreference: INT _ INT.LAST; bestHost: ROPE _ NIL; IF entry = NIL THEN RETURN[NIL]; FOR list: LIST OF IPNameCache.MXHostInfo _ entry.mxHosts, list.rest UNTIL list = NIL DO IF list.first.preference < bestPreference THEN bestPreference _ list.first.preference; ENDLOOP; FOR list: LIST OF IPNameCache.MXHostInfo _ entry.mxHosts, list.rest UNTIL list = NIL DO IF list.first.preference = bestPreference THEN {sorted _ IPNameSupport.MakeRopeInList[sorted, list.first.host]}; ENDLOOP; DO prevBestPreference _ bestPreference; bestPreference _ INT.LAST; FOR list: LIST OF IPNameCache.MXHostInfo _ entry.mxHosts, list.rest UNTIL list = NIL DO IF list.first.preference < bestPreference AND list.first.preference > prevBestPreference THEN {bestPreference _ list.first.preference}; ENDLOOP; IF bestPreference = INT.LAST THEN EXIT; FOR list: LIST OF IPNameCache.MXHostInfo _ entry.mxHosts, list.rest UNTIL list = NIL DO IF list.first.preference = bestPreference THEN {sorted _ IPNameSupport.MakeRopeInList[sorted, list.first.host]}; ENDLOOP; ENDLOOP; RETURN[sorted]; }; <> Source: PUBLIC PROC [name: Rope.ROPE, type: IPName.ExternalSourceCache] RETURNS [server: Rope.ROPE _ NIL] = { SELECT type FROM nameCache => { entry: NameEntry _ IPNameCache.NameLookup[name]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; aliasCache=> { entry: AliasEntry _ IPNameCache.AliasLookup[name]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; mxCache => { entry: MXEntry _ IPNameCache.MXLookup[name]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; bogusNameCache => { entry: BogusNameEntry _ IPNameCache.BogusNameLookup[name]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; addressCache => { entry: AddressEntry _ IPNameCache.AddressLookup[NameToAddress[name].first]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; bogusAddressCache => { entry: BogusAddressEntry _ IPNameCache.BogusAddressLookup[NameToAddress[name].first]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; zoneCache => { entry: ZoneEntry _ IPNameCache.ZoneLookup[name]; IF entry = NIL THEN RETURN[NIL]; server _ AddressToName[entry.source]}; ENDCASE; }; AddressError: ERROR = CODE; ParseAddress: PROC [s: IO.STREAM] RETURNS [a: IPDefs.Address] = { <> ENABLE IO.EndOfStream => GOTO EndOfStream; c: CHAR; WHILE (c _ IO.GetChar[s])=' OR c='\t DO ENDLOOP; IF c = '[ THEN c _ IO.GetChar[s]; FOR i: CARDINAL IN [0..3] DO b: CARDINAL _ 0; IF ~Ascii.Digit[c] THEN ERROR AddressError; DO SELECT c FROM IN ['0..'9] => b _ b*10 + (c-'0); '. => IF i<3 THEN {c _ IO.GetChar[s]; EXIT} ELSE ERROR AddressError; '] => IF i=3 THEN EXIT ELSE ERROR AddressError; ENDCASE => IF i=3 THEN {IO.Backup[s, c]; EXIT} ELSE ERROR AddressError; c _ IO.GetChar[s]; ENDLOOP; IF b > IPDefs.Byte.LAST THEN ERROR AddressError; a[i] _ b; ENDLOOP; EXITS EndOfStream => ERROR AddressError; }; LoadCacheFromAddress: PUBLIC PROC [address: IPDefs.Address, takeOld: BOOL] RETURNS [state: IPName.AddressState] = { entry: AddressEntry; bogus, down: BOOL; IF address = IPDefs.nullAddress THEN RETURN[bogus]; [entry, bogus, down] _ FetchAddressEntry[address, takeOld]; IF bogus THEN RETURN[bogus]; IF down THEN RETURN[down]; IF entry = NIL THEN RETURN[down]; entry.addressCacheLoad _ entry.addressCacheLoad.SUCC; RETURN[addressOk]; }; NormalizeName: PUBLIC PROC [name: ROPE] RETURNS [ROPE] = { entry: NameEntry; bogus, down, mx, alias: BOOL; FOR list: LIST OF Rope.ROPE _ IPConfig.specialDomains, list.rest UNTIL list = NIL DO domain: Rope.ROPE _ list.first; IF DotTailed[name, domain] THEN RETURN[NIL]; ENDLOOP; IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".ARPA"]; name _ FixupTail[name, ".AG"]; name _ FixupTail[name, ".ArpaGateway"]; name _ FixupTail[name, ".NotArpa"]; name _ FixupTail[name, ".ARPA.ARPA"]; -- Hardy 10.0 always adds .ArpaGateway IF Rope.Length[name] > 2 AND Rope.Fetch[name, 0] = '[ THEN { IF Tailed[name, ".ARPA"] THEN name _ StripTail[name, ".ARPA"]; RETURN [name]; }; [entry, bogus, down, mx, alias] _ FetchNameEntry[name, TRUE]; IF down THEN RETURN[name]; IF bogus THEN RETURN[NIL]; IF alias THEN RETURN[IPNameCache.AliasLookup[name].name]; IF entry # NIL THEN { entry.normalizeName _ entry.normalizeName.SUCC; RETURN[entry.name]; }; IF mx THEN RETURN[name]; RETURN[NIL]; }; AddressToName: PUBLIC PROC [address: IPDefs.Address] RETURNS [name: ROPE] = { entry: AddressEntry; bogus, down: BOOL; IF address = IPDefs.nullAddress THEN RETURN[NIL]; [entry, bogus, down] _ FetchAddressEntry[address, TRUE]; IF entry = NIL THEN RETURN[AddressToRope[address]]; entry.addressToName _ entry.addressToName.SUCC; name _ entry.names.first; FOR list: LIST OF ROPE _ entry.names.rest, list.rest UNTIL list = NIL DO name _ PickBestName[name, list.first]; ENDLOOP; RETURN; }; MyAddressToName: PROC [address: IPDefs.Address] RETURNS [name: ROPE] = { entry: AddressEntry; IF address = IPDefs.nullAddress THEN RETURN[NIL]; entry _ IPNameCache.AddressLookup[address]; IF entry # NIL THEN { entry.addressToName _ entry.addressToName.SUCC; name _ entry.names.first; FOR list: LIST OF ROPE _ entry.names.rest, list.rest UNTIL list = NIL DO name _ PickBestName[name, list.first]; ENDLOOP; }; RETURN[AddressToRope[address]]; }; AddressToRope: PUBLIC PROC [a: IPDefs.Address] RETURNS [result: ROPE] = { result _ IO.PutFR["[%g.%g.%g.%g]", [cardinal[a[0]]], [cardinal[a[1]]], [cardinal[a[2]]], [cardinal[a[3]]]]; }; FetchNameEntry: PROC [name: ROPE, takeOld: BOOL _ FALSE] <> RETURNS [entry: NameEntry _ NIL, bogus, down, mx, alias: BOOL_ FALSE] = { DoQuery: PROC [name: ROPE] RETURNS[down, bogus: BOOL _ FALSE] = { reply: BOOL _ FALSE; -- Do zone and mx queries if necessary to guarantee entries are in cache by the time n_a query happens [down, bogus] _ LoadZones[name]; IF down OR bogus THEN RETURN; reply _ Query["MX Query", name, mx]; IF IPNameCache.BogusNameLookup[name] # NIL THEN RETURN[FALSE, TRUE]; IF ~reply THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN; }; reply _ Query["Name Query", name, name]; IF ~reply THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN; }; }; [entry, bogus, down, alias, mx] _ LookInNameCache[name, takeOld]; IF mx OR alias OR bogus OR down THEN RETURN; IF entry # NIL THEN {IF entry.authoritative OR takeOld THEN RETURN; }; [down, bogus] _ DoQuery[name]; IF down OR bogus THEN RETURN; [entry, bogus, down, alias, mx] _ LookInNameCache[name, takeOld]; IF mx OR alias OR bogus OR down THEN RETURN; IF entry # NIL THEN {IF entry.authoritative OR takeOld THEN RETURN; }; IF takeOld THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN; }; CheckNewServers[name]; [down, bogus] _ DoQuery[name]; IF down OR bogus THEN RETURN; [entry, bogus, down, alias, mx] _ LookInNameCache[name, takeOld]; IF mx OR alias OR bogus OR down THEN RETURN; IF entry # NIL THEN {IF entry.authoritative OR takeOld THEN RETURN; }; [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN; }; loopStop: INT _ 10; -- shouldn't be recursion to this extent LoadZones: PROC [name: ROPE, queryAddress: IPDefs.Address _ IPDefs.nullAddress] RETURNS[down, bogus: BOOL_FALSE]= { reply: BOOL _ FALSE; loopCtr: INT _ 0; childZone: ROPE _ NIL; lastChildZone: ROPE _ NIL; zone: ZoneEntry _ BestZone[name]; IF zone = NIL THEN { topZone: ROPE _ TopLevelZone[name]; reply _ Query["Zone Query", topZone, newZone, queryAddress]; {bogusEntry: BogusNameEntry _ IPNameCache.BogusNameLookup[topZone]; IF bogusEntry # NIL THEN { InsertBogusName[bogusEntry.source, bogusTTL, bogusEntry.authoritative, name]; RETURN[FALSE, TRUE]}; }; IF ~reply OR BestZone[name] = NIL THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN}; }; DO zone _ BestZone[name]; reply _ FALSE; IF ~zone.authoritative THEN { reply _ Query["Zone Query", zone.zone, newZone, queryAddress]; IF ~reply THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN}; }; IF Tailed[name, "IN-ADDR.ARPA"] THEN childZone _ name ELSE { IF Rope.Equal[zone.zone, name, FALSE] THEN EXIT; IF Rope.Equal[lastChildZone, name, FALSE] THEN EXIT; childZone _ ChildZone[name, zone.zone]; IF childZone = NIL THEN EXIT; IF Rope.Equal[childZone, zone.zone, FALSE] THEN EXIT; IF Rope.Equal[childZone, lastChildZone, FALSE] THEN EXIT; IF Tailed[childZone, "ARPA"] THEN EXIT; }; reply _ Query["Zone Query", childZone, newZone, queryAddress]; {bogusEntry: BogusNameEntry _ IPNameCache.BogusNameLookup[childZone]; IF bogusEntry # NIL THEN { InsertBogusName[bogusEntry.source, bogusTTL, bogusEntry.authoritative, name]; RETURN[FALSE, TRUE]}; }; IF ~reply THEN { [] _ IPNameCache.UpdateDownName[name, downTTL]; down _ TRUE; RETURN}; lastChildZone _ childZone; IF SameZone[BestZone[name], zone] THEN EXIT; IF loopCtr = loopStop THEN EXIT; -- beware of bogus reponses causing infinite loop loopCtr _ loopCtr +1; ENDLOOP; }; SameZone: PROC[zone1, zone2: ZoneEntry] RETURNS [same: BOOL _ TRUE] = { IF zone1 = NIL AND zone2 = NIL THEN RETURN[TRUE]; IF zone1 = NIL OR zone2 = NIL THEN RETURN[FALSE]; IF zone1.source # zone2.source THEN RETURN[FALSE]; IF zone1.authoritative # zone2.authoritative THEN RETURN[FALSE]; IF ~Rope.Equal[zone1.zone, zone2.zone, FALSE] THEN RETURN[FALSE]; IF ~RopeList.EqualLists[zone1.servers, zone2.servers, FALSE] THEN RETURN[FALSE]; RETURN[TRUE]; }; LookInNameCache: PROC [name: ROPE, takeOld: BOOL] RETURNS [entry: NameEntry_ NIL, bogus: BOOL_ FALSE, down: BOOL_ FALSE, alias: BOOL_ FALSE, mx: BOOL_ FALSE] = { <<[NIL, FALSE, FALSE, FALSE, FALSE] => Don't know>> <<>> bogusEntry: BogusNameEntry; aliasEntry: AliasEntry; downEntry: DownNameEntry; mxEntry: MXEntry; entry _ IPNameCache.NameLookup[name]; IF entry # NIL THEN { IF ~takeOld THEN entry _ MaybeRejuvinateName[entry]; }; mxEntry _ IPNameCache.MXLookup[name]; IF mxEntry # NIL THEN { IF ~takeOld THEN mxEntry _ MaybeRejuvinateMX[mxEntry]; IF mxEntry = NIL THEN mx _ FALSE -- Can't rejuvinate an MX record ELSE { mx _ TRUE; mxEntry.nameToMX _ mxEntry.nameToMX.SUCC}; }; aliasEntry _ IPNameCache.AliasLookup[name]; IF aliasEntry # NIL THEN { IF ~takeOld THEN aliasEntry _ MaybeRejuvinateAlias[aliasEntry]; IF aliasEntry = NIL THEN alias _ FALSE -- Can't rejuvinate an Alias ELSE { alias _ TRUE; aliasEntry.aliasToName _ aliasEntry.aliasToName.SUCC}; }; bogusEntry _ IPNameCache.BogusNameLookup[name]; IF bogusEntry # NIL THEN { IF ~takeOld THEN bogusEntry _ MaybeRejuvinateBogusName[bogusEntry]; IF bogusEntry = NIL THEN bogus _ FALSE -- Can't rejuvinate a Bogus name ELSE { bogus _ TRUE; bogusEntry.nameToBogus _ bogusEntry.nameToBogus.SUCC}; }; downEntry _ IPNameCache.DownNameLookup[name]; IF downEntry # NIL THEN { IF ~takeOld THEN downEntry _ MaybeRejuvinateDownName[downEntry]; IF downEntry = NIL THEN down _ FALSE -- time to check name ELSE { down _ TRUE; downEntry.nameToDown _ downEntry.nameToDown.SUCC}; }; }; AddressToQueryRope: PROC [address: IPDefs.Address] RETURNS[rope: ROPE] = { rope _ IO.PutFR["%G.%G.%G.%G.IN-ADDR.ARPA", [integer[address[3]]], [integer[address[2]]], [integer[address[1]]], [integer[address[0]]]]; }; FetchAddressEntry: PROC [address: IPDefs.Address, takeOld: BOOL] RETURNS [entry: AddressEntry_NIL, bogus: BOOL _ FALSE, down: BOOL _ FALSE] = { <<[NIL, FALSE, FALSE] => Don't know>> servers, newServers: LIST OF IPDefs.Address _ NIL; reply: BOOL _ FALSE; addressRope: ROPE _ AddressToQueryRope[address]; entry _ IPNameCache.AddressLookup[address]; IF entry = NIL THEN { bogusEntry: BogusAddressEntry _ IPNameCache.BogusAddressLookup[address]; IF bogusEntry # NIL THEN { IF ~takeOld THEN { bogusEntry _ MaybeRejuvinateBogusAddress[bogusEntry]; IF bogusEntry = NIL THEN RETURN[NIL, FALSE, FALSE]; }; }; -- Can't rejuvinate a Bogus Address IF bogusEntry # NIL THEN { bogusEntry.addressToBogus _ bogusEntry.addressToBogus.SUCC; RETURN[NIL, TRUE, FALSE]; }; }; -- We are sure this address is bogus IF entry # NIL THEN { IF ~takeOld THEN { entry _ MaybeRejuvinateAddress[entry]; IF entry = NIL THEN RETURN[NIL, FALSE, FALSE]; }; }; -- Can't rejuvinate an Address IF entry # NIL THEN RETURN; -- We are sure this address is valid IF entry = NIL THEN { downEntry: DownAddressEntry _ IPNameCache.DownAddressLookup[address]; IF downEntry # NIL THEN downEntry _ MaybeRejuvinateDownAddress[downEntry]; IF downEntry = NIL THEN down _ FALSE; -- time to check name IF downEntry # NIL THEN { downEntry.addressToDown _ downEntry.addressToDown.SUCC; RETURN[NIL, FALSE, TRUE]; }; }; [down, bogus] _ LoadZones[addressRope, address]; IF bogus THEN RETURN; IF down THEN { [] _ IPNameCache.UpdateDownAddress[address, downTTL]; RETURN; }; reply _ Query["Address Query", addressRope, address, address]; IF ~reply THEN { [] _ IPNameCache.UpdateDownAddress[address, downTTL]; down _ TRUE; RETURN; }; entry _ IPNameCache.AddressLookup[address]; -- We are sure this address is valid }; FixupTail: PROC [old, tail: ROPE] RETURNS [new: ROPE] = { new _ old; IF Tailed[old, tail] THEN { new _ StripTail[old, tail]; new _ Rope.Concat[new, ".ARPA"]; }; }; DotTailed: PROC [body, tail: ROPE] RETURNS [match: BOOL] = { IF ~Tailed[body, tail] THEN RETURN[FALSE]; IF Rope.Fetch[body, Rope.Length[body]-Rope.Length[tail]-1] # '. THEN RETURN[FALSE]; RETURN[TRUE]; }; Tailed: PROC [body, tail: ROPE] RETURNS [match: BOOL] = { bodyLength: INT = Rope.Length[body]; tailLength: INT = Rope.Length[tail]; back: ROPE; IF bodyLength <= tailLength THEN RETURN[FALSE]; back _ Rope.Substr[body, bodyLength-tailLength, tailLength]; IF ~Rope.Equal[back, tail, FALSE] THEN RETURN[FALSE]; RETURN[TRUE]; }; StripTail: PROC [body, tail: ROPE] RETURNS [new: ROPE] = { bodyLength: INT = body.Length[]; tailLength: INT = tail.Length[]; RETURN[Rope.Substr[body, 0, bodyLength - tailLength]]}; PickBestName: PUBLIC PROC [a, b: ROPE] RETURNS [ROPE] = { <> <> <> <> IF a = NIL THEN RETURN[b]; IF b = NIL THEN RETURN[a]; IF ~Tailed[a, ".ARPA"] THEN RETURN[a]; IF ~Tailed[b, ".ARPA"] THEN RETURN[b]; IF Gateway[a] THEN RETURN[b]; IF Gateway[b] THEN RETURN[a]; IF Dots[a] < Dots[b] THEN RETURN[a]; RETURN[b]; }; Gateway: PROC [name: ROPE] RETURNS [match: BOOL] = { IF Tailed[name, "-GW.ARPA"] THEN RETURN[TRUE]; IF Tailed[name, "-GATEWAY.ARPA"] THEN RETURN[TRUE]; RETURN[FALSE]; }; Dots: PROC [name: ROPE] RETURNS [dots: INT _ 0] = { FOR i: INT IN [0..Rope.Length[name]) DO IF Rope.Fetch[name, i] = '. THEN dots _ dots+1; ENDLOOP; }; Class: TYPE = IPNameUdp.Class; DomainHeader: TYPE = IPNameUdp.DomainHeader; Type: TYPE = IPNameUdp.Type; FindServers: PROCEDURE [name: ROPE] RETURNS [answers: LIST OF IPDefs.Address _ NIL] = { bestZone: ZoneEntry _ BestZone[name]; nameEntry: NameEntry _ IPNameCache.NameLookup[name]; serverList: LIST OF ROPE _ NIL; <> <> <> <> <<>> IF nameEntry # NIL THEN IF nameEntry.authoritative = TRUE THEN answers _ IPNameSupport.MakeAddressInList[answers, nameEntry.source]; IF bestZone = NIL THEN serverList _ rootServers ELSE serverList _ bestZone.servers; <<>> FOR list: LIST OF ROPE _ serverList, list.rest UNTIL list = NIL DO serverName: ROPE _ list.first; server: NameEntry _ IPNameCache.NameLookup[serverName]; -- Beware of recursion best: IPDefs.Address; IF server = NIL THEN LOOP; IF server.addresses = NIL THEN LOOP; best _ IPRouter.BestAddress[server.addresses]; IF IPNameCache.DownServerLookup[best] # NIL THEN LOOP; answers _ IPNameSupport.MakeAddressInList[answers, best]; ENDLOOP; FOR list: LIST OF ROPE _ serverList, list.rest UNTIL list = NIL DO serverName: ROPE _ list.first; server: NameEntry _ IPNameCache.NameLookup[serverName]; -- Beware of recursion IF server = NIL THEN LOOP; FOR list: LIST OF IPDefs.Address _ server.addresses, list.rest UNTIL list = NIL DO IF IPNameCache.DownServerLookup[list.first] # NIL THEN LOOP; answers _ IPNameSupport.MakeAddressInList[answers, list.first]; ENDLOOP; ENDLOOP; IF answers # NIL THEN RETURN[answers]; IF bestZone # NIL THEN RETURN[NIL]; -- All domain servers down <> FOR list: LIST OF IPDefs.Address _ rootServerAddresses, list.rest UNTIL list = NIL DO IF IPNameCache.DownServerLookup[list.first] # NIL THEN LOOP; answers _ IPNameSupport.MakeAddressInList[answers, list.first]; ENDLOOP; RETURN[answers]; }; BestZone: PROCEDURE [name: ROPE] RETURNS[bestZone: ZoneEntry_NIL] = { zones: LIST OF ZoneEntry = IPNameCache.GetZones[]; bestZoneName: ROPE _ NIL; bestZoneLength: INT _ 0; FOR list: LIST OF ZoneEntry _ zones, list.rest UNTIL list = NIL DO zone: ZoneEntry _ list.first; zoneName: ROPE _ zone.zone; zoneLength: INT _ Rope.Length[zoneName]; IF zoneLength < bestZoneLength THEN LOOP; IF Rope.Equal[name, zoneName, FALSE] OR DotTailed[name, zoneName] THEN { bestZone _ zone; bestZoneLength _ zoneLength; }; ENDLOOP; }; CheckNewServers: PROCEDURE [name: ROPE] = { zone: ZoneEntry _ IPNameCache.GetZone[name]; IF zone = NIL THEN RETURN; FOR list: LIST OF ROPE _ zone.servers, list.rest UNTIL list = NIL DO serverName: ROPE _ list.first; entry: NameEntry _ IPNameCache.NameLookup[serverName]; IF entry # NIL AND entry.authoritative THEN LOOP; [] _ Query["New Server", serverName, newServer]; ENDLOOP; IF zone.authoritative THEN RETURN; [] _ Query["New Zone", zone.zone, newZone]; }; rejuvinationThreshold: INT = -60; MaybeRejuvinateName: PROCEDURE [entry: NameEntry] RETURNS [NameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, name]; RETURN[entry]; }; {bestZone: ZoneEntry _ BestZone[entry.name]; IF bestZone # NIL THEN [] _ MaybeRejuvinateZone[bestZone];}; [] _ Query["Name Rejuvenation", entry.name, nameRejuvination]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateAlias: PROCEDURE [entry: AliasEntry] RETURNS [AliasEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, alias]; RETURN[entry]; }; [] _ Query["Alias Rejuvenation", entry.alias, aliasRejuvination]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateMX: PROCEDURE [entry: MXEntry] RETURNS [MXEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, mx]; RETURN[entry]; }; [] _ Query["MX Rejuvenation", entry.name, mxRejuvination]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateBogusName: PROCEDURE [entry: BogusNameEntry] RETURNS [BogusNameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, bogusName]; RETURN[entry]; }; [] _ Query["Bogus Name Rejuvenation", entry.bogus, bogusNameRejuvination]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateDownName: PROCEDURE [entry: DownNameEntry] RETURNS [DownNameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN RETURN[entry]; RETURN[NIL]; }; -- Time to check name again MaybeRejuvinateAddress: PROCEDURE [entry: AddressEntry] RETURNS [AddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, address]; RETURN[entry]; }; [] _ Query["Address Rejuvenation", AddressToQueryRope[entry.address], addressRejuvination, entry.address]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateBogusAddress: PROCEDURE [entry: BogusAddressEntry] RETURNS [BogusAddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { IPNameCache.AddToCacheHits[entry.source, bogusAddress]; RETURN[entry]; }; [] _ Query["Bogus Address Rejuvenation", AddressToQueryRope[entry.bogus], bogusAddressRejuvination, entry.bogus]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; MaybeRejuvinateDownAddress: PROCEDURE [entry: DownAddressEntry] RETURNS [DownAddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN RETURN[entry]; RETURN[NIL]; }; MaybeRejuvinateZone: PROCEDURE [entry: ZoneEntry] RETURNS [ZoneEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; ttl: INT _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold AND entry.authoritative THEN {IPNameCache.AddToCacheHits[entry.source, zone]; RETURN[entry]; }; [] _ Query["Zone Rejuvenation", entry.zone, zoneRejuvination]; ttl _ BasicTime.Period[from: now, to: entry.expires]; IF ttl > rejuvinationThreshold THEN { entry.rejuvinations _ entry.rejuvinations.SUCC; RETURN[entry]; }; entry.expires _ BasicTime.Update[now, ttlDefault]; -- Don't thrash RETURN[NIL]; }; nQueries: CARDINAL _ 3; -- Number of query tries with timeouts below baseTimeout: CARDINAL _ 5; -- 5, 10, 15 seconds Query: PROCEDURE [ what: ROPE, name: ROPE, type: IPNameCache.ProbeType, queryAddress: IPDefs.Address _ IPDefs.nullAddress] RETURNS[done: BOOL _ FALSE] = TRUSTED { packetStart, packetStop: BasicTime.Pulses; milliseconds: LONG CARDINAL; id: CARDINAL _ (sequenceNumber _ sequenceNumber.SUCC); servers: LIST OF IPDefs.Address _ FindServers[name]; FOR list: LIST OF IPDefs.Address _ servers, list.rest UNTIL done OR list = NIL DO server: IPDefs.Address _ list.first; handle: UDP.Handle; handle _ UDP.Create[him: server, remote: UDP.domain, local: UDP.default]; IPNameCache.AddToProbes[server, type]; BEGIN ENABLE ServerIsDown => { IPNameSupport.LogRope[IO.PutFR["%T ** ServerDown during %G for %G via %G.\n", [time[BasicTime.Now[]]], [rope[what]], [rope[name]], [rope[MyAddressToName[server]]]]]; CONTINUE; }; FOR i: CARDINAL IN [1..nQueries] UNTIL done DO dg: IPDefs.Datagram _ NEW [IPDefs.DatagramRec]; udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@dg.data]; domain: LONG POINTER TO DomainHeader _ LOOPHOLE[@udp.data]; qType: IPNameUdp.Type _ a; domain^ _ [id: id]; udp.length _ UDP.minLength + DomainHeader.SIZE*2; IF type = newZone OR type = zoneRejuvination THEN qType _ ns; IF type = mx OR type = mxRejuvination THEN qType _ mx; IF type = address THEN qType _ star; IPNameUdp.AppendQuery[udp, domain, name, qType, in]; UDP.Send[handle, dg, udp.length]; packetStart _ BasicTime.GetClockPulses[]; UNTIL done OR (dg _ UDP.Receive[handle, i*1000*baseTimeout]) = NIL DO packetStop _ BasicTime.GetClockPulses[]; milliseconds _ BasicTime.PulsesToMicroseconds[packetStop-packetStart]/1000; udp _ LOOPHOLE[@dg.data]; domain _ LOOPHOLE[@udp.data]; IF dg.inHdr.source # server THEN IPNameSupport.LogRope[IO.PutFR["Strange source address: expected %G, found %G = %G: \n", [rope[AddressToRope[server]]], [rope[AddressToRope[dg.inHdr.source]]], [rope[MyAddressToName[dg.inHdr.source]]]]]; done _ ProcessReply[udp, domain, dg.inHdr.source, queryAddress]; IPNameCache.AddToCounter[server, milliseconds]; IPNameSupport.LogRope[IO.PutFR["%G for %G took %G ms via %G.\n", [rope[what]], [rope[name]], [integer[milliseconds]], [rope[MyAddressToName[server]]]]]; dg _ NIL; ENDLOOP; IF ~done THEN IPNameCache.AddToLost[server]; ENDLOOP; IF ~done THEN {IPNameSupport.LogRope[IO.PutFR["%T ** No response to %G for %G via %G.\n", [time[BasicTime.Now[]]], [rope[what]], [rope[name]], [rope[MyAddressToName[server]]]]]; [] _ IPNameCache.UpdateDownServer[server, downTTL]; }; END; UDP.Destroy[handle]; ENDLOOP; IF ~done THEN { IPNameSupport.LogRope[IO.PutFR["%T ** No response to %G for %G from any server.\n", [time[BasicTime.Now[]]], [rope[what]], [rope[name]]]]; }; }; ServerIsDown: SIGNAL = CODE; LikelyValidReply: PROC [name: ROPE, source: IPDefs.Address, bogus: BOOL _TRUE] RETURNS[ok: BOOL] = { zone: ZoneEntry; servers: LIST OF ROPE _ NIL; addresses: LIST OF IPDefs.Address _ NIL; IF bogus AND IPNameCache.NameLookup[name] # NIL THEN RETURN[FALSE]; IF bogus AND IPNameCache.MXLookup[name] # NIL THEN RETURN[FALSE]; IF bogus AND IPNameCache.AliasLookup[name] # NIL THEN RETURN[FALSE]; zone _ IPNameCache.ZoneLookup[name]; IF zone = NIL THEN zone _ IPNameCache.ZoneLookup[BestZoneFromName[name]]; IF zone = NIL THEN RETURN[TRUE]; addresses _ ServerListToAddressList[zone.servers]; IF ~IPNameSupport.AddressInList[addresses, source] THEN RETURN[FALSE]; RETURN[TRUE]; }; ServerListToAddressList: PROC [servers: LIST OF ROPE] RETURNS[answers: LIST OF IPDefs.Address _ NIL] = { FOR list: LIST OF ROPE _ servers, list.rest UNTIL list = NIL DO serverName: ROPE _ list.first; serverEntry: NameEntry _ IPNameCache.NameLookup[serverName]; IF serverEntry = NIL THEN LOOP; FOR addresses: LIST OF IPDefs.Address _ serverEntry.addresses, addresses.rest UNTIL addresses = NIL DO answers _ IPNameSupport.MakeAddressInList[answers, addresses.first]; ENDLOOP; ENDLOOP; }; BestZoneFromName: PROC [name: ROPE] RETURNS[ROPE] = { startPos: INT _ 0; nameLength: INT; IF name = NIL THEN RETURN[NIL]; nameLength _ name.Length[]; FOR i: INT IN [0..nameLength) DO IF Rope.Fetch[name, i] = '. THEN {startPos _ i+1; EXIT;}; ENDLOOP; RETURN[Rope.Substr[name, startPos, nameLength-startPos]]; }; TopLevelZone: PROC [name: ROPE] RETURNS[ROPE] = { startPos: INT _ 0; nameLength: INT; IF name = NIL THEN RETURN[NIL]; nameLength _ name.Length[]; FOR i: INT DECREASING IN [0..nameLength) DO IF Rope.Fetch[name, i] = '. THEN {startPos _ i+1; EXIT;}; ENDLOOP; RETURN[Rope.Substr[name, startPos, nameLength]]; }; ChildZone: PROC [name: ROPE, parentZone: ROPE_ NIL] RETURNS[ROPE] = { startPos: INT _ 0; nameLength: INT; parentLength: INT; IF name = NIL THEN RETURN[NIL]; IF parentZone = NIL THEN RETURN[TopLevelZone[name]]; nameLength _ name.Length[]; parentLength _ parentZone.Length[]; FOR i: INT DECREASING IN [0..nameLength-parentLength-1) DO IF Rope.Fetch[name, i] = '. THEN {startPos _ i+1; EXIT;}; ENDLOOP; RETURN[Rope.Substr[name, startPos, nameLength]]; }; SelfMX: PROC [mxEntry: MXEntry, name: ROPE] RETURNS[yes: BOOL_ FALSE] = { IF mxEntry = NIL OR name = NIL THEN RETURN[FALSE]; FOR list: LIST OF IPNameCache.MXHostInfo _ mxEntry.mxHosts, list.rest UNTIL list = NIL DO IF Rope.Equal[list.first.host, name, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; ProcessReply: PROC [ -- Smashes udp.length udp: LONG POINTER TO UDP.BodyRec, domain: LONG POINTER TO DomainHeader, source: IPDefs.Address, queryAddress: IPDefs.Address_ IPDefs.nullAddress] RETURNS[done: BOOLEAN_TRUE] = TRUSTED { ENABLE {UNWIND => NULL; IPNameUdp.EndOfData => GOTO Quit}; qname: ROPE; qtype: Type; qclass: Class; udp.length _ UDP.minLength + DomainHeader.SIZE*2; IF domain.qr # response THEN RETURN[FALSE]; IF domain.tc THEN RETURN[FALSE]; SELECT domain.rcode FROM ok => NULL; format => RETURN[TRUE]; nameNotFound => { name: ROPE _ IPNameUdp.GetName[udp]; <> IF LikelyValidReply[name, source] AND domain.aa THEN InsertBogusName[source, bogusTTL, domain.aa, name] ELSE RETURN[FALSE]; RETURN[TRUE]; }; serverFailed, notImplemented, refused => SIGNAL ServerIsDown; ENDCASE => ERROR; FOR i: INT IN [0..domain.qdCount) DO qname _ IPNameUdp.GetName[udp]; qtype _ IPNameUdp.GetTwoBytes[udp]; qclass _ IPNameUdp.GetTwoBytes[udp]; ENDLOOP; IF domain.anCount = 0 THEN { < mx, or zone, or server is confused !>> <<>> IF qtype = mx AND IPNameCache.ZoneLookup[qname] = NIL AND LikelyValidReply[qname, source, FALSE] THEN { SELECT TRUE FROM domain.nsCount # 0 => RETURN[FALSE]; -- server is confused ! Try another server. domain.nsCount = 0 => MergeMXInfo[source, mxTTL, domain.aa, qname, qname, 0]; ENDCASE; }; IF qtype = a AND IPNameCache.ZoneLookup[qname] # NIL AND LikelyValidReply[qname, source, TRUE] AND domain.aa THEN {InsertBogusName[source, bogusTTL, domain.aa, qname]; RETURN[TRUE];}; {mxEntry: MXEntry _ IPNameCache.MXLookup[qname]; IF qtype = a AND SelfMX[mxEntry, qname] AND LikelyValidReply[qname, source, FALSE] THEN RETURN[FALSE]; -- server is confused! Try another server. }; }; FOR i: INT IN [0..domain.anCount) DO name: ROPE _ IPNameUdp.GetName[udp]; type: Type _ IPNameUdp.GetTwoBytes[udp]; class: Class _ IPNameUdp.GetTwoBytes[udp]; ttl: INT _ IPNameUdp.GetTtl[udp]; rDataLength: CARDINAL _ IPNameUdp.GetTwoBytes[udp]; SELECT TRUE FROM type = a AND class = in => { address: IPDefs.Address _ IPNameUdp.GetIPAddress[udp]; MergeNameInfo[source, ttl, domain.aa, name, address]; }; type = cName AND class = in => { alias: ROPE _ name; real: ROPE _ IPNameUdp.GetName[udp]; MergeAliasInfo[source, ttl, domain.aa, real, alias]; }; type = mx AND class = in => { preference: INT _ IPNameUdp.GetCardinal[udp]; host: ROPE _ IPNameUdp.GetName[udp]; MergeMXInfo[source, ttl, domain.aa, name, host, preference]}; type = ns AND class = in => { zone: ROPE _ name; server: ROPE _ IPNameUdp.GetName[udp]; IF Rope.Length[zone] # 0 THEN <> MergeServerInfo[source, ttl, domain.aa, zone, server]; }; type = ptr AND class = in => { nameForAddress: ROPE _ IPNameUdp.GetName[udp]; MergeAddressInfo[source, ttl, domain.aa, queryAddress, nameForAddress]; }; ENDCASE => udp.length _ udp.length + rDataLength; ENDLOOP; FOR i: INT IN [0..domain.nsCount) DO name: ROPE _ IPNameUdp.GetName[udp]; type: Type _ IPNameUdp.GetTwoBytes[udp]; class: Class _ IPNameUdp.GetTwoBytes[udp]; ttl: INT _ IPNameUdp.GetTtl[udp]; rDataLength: CARDINAL _ IPNameUdp.GetTwoBytes[udp]; SELECT TRUE FROM type = ns AND class = in => { zone: ROPE _ name; server: ROPE _ IPNameUdp.GetName[udp]; IF Rope.Length[zone] # 0 THEN <> MergeServerInfo[source, ttl, FALSE, zone, server]; }; ENDCASE => udp.length _ udp.length + rDataLength; ENDLOOP; FOR i: INT IN [0..domain.arCount) DO name: ROPE _ IPNameUdp.GetName[udp]; type: Type _ IPNameUdp.GetTwoBytes[udp]; class: Class _ IPNameUdp.GetTwoBytes[udp]; ttl: INT _ IPNameUdp.GetTtl[udp]; rDataLength: CARDINAL _ IPNameUdp.GetTwoBytes[udp]; SELECT TRUE FROM type = a AND class = in => { address: IPDefs.Address _ IPNameUdp.GetIPAddress[udp]; MergeNameInfo[source, ttl, FALSE, name, address]; }; type = cName AND class = in => { alias: ROPE _ name; real: ROPE _ IPNameUdp.GetName[udp]; MergeAliasInfo[source, ttl, FALSE, real, alias]; }; type = mx AND class = in => { preference: INT _ IPNameUdp.GetCardinal[udp]; host: ROPE _ IPNameUdp.GetName[udp]; MergeMXInfo[source, ttl, FALSE, name, host, preference]}; type = ns AND class = in => { zone: ROPE _ name; server: ROPE _ IPNameUdp.GetName[udp]; IF Rope.Length[zone] # 0 THEN <> MergeServerInfo[source, ttl, FALSE, zone, server]; }; ENDCASE => udp.length _ udp.length + rDataLength; ENDLOOP; EXITS Quit => RETURN[FALSE]; }; MergeNameInfo: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, name: ROPE, address: IPDefs.Address] = { entry: NameEntry _ IPNameCache.UpdateName[name, source, ttl, authoritative]; IF entry = NIL THEN RETURN; IPNameCache.AddAddressToName[entry, address]; IPNameSupport.NameSummaryLine[entry, TRUE]; }; MergeAliasInfo: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, name, alias: ROPE] = { entry: AliasEntry _ IPNameCache.UpdateAlias[alias, source, ttl, authoritative]; IF entry = NIL THEN RETURN; IPNameCache.AddNameToAlias[entry, name]; IPNameSupport.AliasSummaryLine[entry, TRUE]; }; MergeAddressInfo: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, address: IPDefs.Address, name: ROPE] = { entry: AddressEntry _ IPNameCache.UpdateAddress[address, source, ttl, authoritative]; IF entry = NIL THEN RETURN; IPNameCache.AddNameToAddress[entry, name]; IPNameSupport.AddressSummaryLine[entry, TRUE]; }; MergeServerInfo: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, zone, server: ROPE] = { now: BasicTime.GMT _ BasicTime.Now[]; entry: ZoneEntry _ IPNameCache.UpdateZone[zone, source, ttl, authoritative]; IF entry = NIL THEN RETURN; IPNameCache.AddServer[entry, server]; IPNameSupport.ZoneSummaryLine[entry, TRUE]; }; MergeMXInfo: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, name, host: ROPE, preference: INT] = { now: BasicTime.GMT _ BasicTime.Now[]; entry: MXEntry _ IPNameCache.UpdateMX[name, source, ttl, authoritative]; IF entry = NIL THEN RETURN; IPNameCache.AddHostToMX[entry, [host, preference]]; IPNameSupport.MXSummaryLine[entry, TRUE]; }; ProcessBogusAddress: PROC [bogus: IPDefs.Address] = { InsertBogusAddress[IPDefs.nullAddress, bogusTTL, FALSE, bogus]; }; InsertBogusAddress: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, bogus: IPDefs.Address] = { [] _ IPNameCache.UpdateBogusAddress[bogus, source, ttl, authoritative]; NULL; }; ProcessBogusName: PROC [bogus: ROPE] = { InsertBogusName[IPDefs.nullAddress, ttlDefault, FALSE, bogus]; }; InsertBogusName: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL, bogus: ROPE] = { [] _ IPNameCache.UpdateBogusName[bogus, source, ttl, authoritative]; NULL; }; END.