IPNameImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Hal Murray September 11, 1985 7:18:37 pm PDT
John Larson, October 7, 1987 9:50:14 pm PDT
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.ROPEIPConfig.rootServers;
LoadCacheFromName: PUBLIC PROC [name: Rope.ROPE, takeOld, needAddress: BOOLFALSE] RETURNS [state: IPName.NameState] = {
takeOld TRUE will avoid cache refresh
needAddress TRUE causes extended lookup, all addresses loaded
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];
};
Return a sorted list of addresses for the name or NIL if the name is not found. Case is ignored. name is allowed to be an Internet address constant of the form "[a.b.c.d]".
NameToAddress: PUBLIC PROC [name: Rope.ROPE, mail: BOOLFALSE]
RETURNS [addresses: LIST OF IPDefs.Address← NIL] = {
entry, mxEntry: NameEntry ← NIL;
bogus: BOOLFALSE;
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;
};
Return sorted list of mail forwarding hosts if MX entry exists. NIL otherwise.
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]]; };
This code should really check for self (Xerox.com) in the mx list and do the right thing ... (see rfc974) For now, I'm assuming only one mail path into Xerox.
SortMXHosts: PROC [entry: MXEntry]
RETURNS [sorted: LIST OF Rope.ROPENIL] = {
bestPreference: INTINT.LAST; -- least is best
prevBestPreference: INTINT.LAST;
bestHost: ROPENIL;
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]; };
Returns name of server responsible for data. Returns NIL if not in cache.
Source: PUBLIC PROC [name: Rope.ROPE, type: IPName.ExternalSourceCache]
RETURNS [server: Rope.ROPENIL] = {
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] = {
Get an internet address (optionally preceded by spaces and tabs and surrounded by [ ]) from the input stream. Raises AddressError for illegal syntax.
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]
takeOld Boolean TRUE forces expedited query
RETURNS [entry: NameEntry ← NIL, bogus, down, mx, alias: BOOLFALSE] = {
DoQuery: PROC [name: ROPE] RETURNS[down, bogus: BOOLFALSE] = {
reply: BOOLFALSE;
-- Do zone and mx queries if necessary to guarantee entries are in cache by the time n𡤊 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: BOOLFALSE]= {
reply: BOOLFALSE;
loopCtr: INT ← 0;
childZone: ROPENIL;
lastChildZone: ROPENIL;
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: BOOLTRUE] = {
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: BOOLFALSE, down: BOOLFALSE, alias: BOOLFALSE, mx: BOOLFALSE] = {
[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: BOOLFALSE, down: BOOLFALSE] = {
[NIL, FALSE, FALSE] => Don't know
servers, newServers: LIST OF IPDefs.Address ← NIL;
reply: BOOLFALSE;
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] = {
mumble.COM is better than mumble.ARPA
mumble.ARPA is better than mumble-GW.ARPA
mumble.ARPA is better than mumble-GATEWAY.ARPA (MARYLAND)
mumble.ARPA is better than mumble.jumble.ARPA (F.ISI.ARPA)
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 ROPENIL;
Brew up the list of addresses to try:
First pass: use best address from each server
Second pass: try back doors
Don't use down server addresses
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
Root server addresses not loaded yet (startup)
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: ROPENIL;
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: BOOLFALSE] = 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: BOOLTRUE] RETURNS[ok: BOOL] = {
zone: ZoneEntry;
servers: LIST OF ROPENIL;
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: BOOLFALSE] = {
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: BOOLEANTRUE] = 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];
Servers sometimes hand out bogus nameNotFounds, so must be careful;
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 {
Name exists, but no address => 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
Root of world is wired into to code - avoid bogus info
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
Root of world is wired into to code - avoid bogus info
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
Root of world is wired into to code - avoid bogus info
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.