package engine import ( "time" "jarl/internal/model" "jarl/internal/render" ) // serialGreater reports whether a > b in RFC 1982 serial number // arithmetic. func serialGreater(a, b uint32) bool { return int32(a-b) > 0 } // NextSerial returns the serial after old under policy, with the same // semantics as BIND's serial-update-method. func NextSerial(old uint32, policy string, now time.Time) uint32 { switch policy { case model.SerialUnixtime: t := uint32(now.Unix()) if serialGreater(t, old) { return t } return old + 1 case model.SerialIncrement: return old + 1 default: // date: YYYYMMDDnn d := dateSerial(now) if serialGreater(d, old) { return d } return old + 1 } } // SerialChange records a serial bump. type SerialChange struct { ZoneID int64 `json:"zone_id"` Zone string `json:"zone"` View string `json:"view,omitempty"` Old uint32 `json:"old"` New uint32 `json:"new"` } // bumpSerials increments the serial of every primary zone in work whose // DNS data differs from base, unless the serial was set explicitly. func bumpSerials(base, work *model.State, now time.Time, user string) []SerialChange { var out []SerialChange for _, z := range work.SortedZones() { if z.Type != model.ZonePrimary { continue } policy := z.SerialPolicy if policy == "" { policy = work.Settings.SerialPolicy } old := base.Zones[z.ID] if old == nil || old.Type != model.ZonePrimary || old.ViewID != z.ViewID { // New to named (or moved): keep the serial it was created // with, which InitialSerial or the source zone provided. continue } if z.SOA.Serial != old.SOA.Serial { // Set explicitly by the user. continue } if render.ZoneContentHash(base, old) == render.ZoneContentHash(work, z) { continue } next := NextSerial(old.SOA.Serial, policy, now) out = append(out, SerialChange{ZoneID: z.ID, Zone: z.Name, View: work.ViewName(z), Old: old.SOA.Serial, New: next}) z.SOA.Serial = next z.Touch(user, now) } return out }