9

I have a dns zone, which has serial number: 2015040500

Today I am going to add some CNAME records there, so I am interested in how to increment serial number, I mean should I change it based on today's date, e.g it will be: 2015042200 or just increment it with one, so it will be 2015040501 ?

Shota
  • 245
  • 1
  • 2
  • 8

5 Answers5

9

You can do however you please, the only thing you must make sure is that the new serial number is greater than the old one.

Having said that, I would recommend a timestamp based approach following a scheme like:

 YYYYMMDDxx

where xx starts at 00 and is incremented for all edits on that specific day (when editing on another day, you reset xx to 00)

The main advantage of this scheme is, that you also know the date of the last modification of your zone-file at first glance.

It also makes the serial number incrementing more robust.

The alternative is to start with 1 and just increment whenever you edit the file.

If the serial number is already timestamp based (and 2015040500 looks very much like that), you shold probably stick with that decision (even if not made by you), and use the logical successor 2015042200

umläute
  • 6,300
  • 1
  • 24
  • 48
1

i decided to use unix time for serial

- name: "{{ role_path|basename }} | get unix time"
  shell: echo $(date +%s)
  register: unix_time_stamp
  delegate_to: localhost
  run_once: true
  become: no

#
- name: "{{ role_path|basename }} setting execution facts"
  set_fact:
    __bind9_zone_serial: "{{ unix_time_stamp.stdout }}"
  run_once: true
  become: no
shcherbak
  • 493
  • 2
  • 10
  • 1
    The idea is interesting, however following the date convention makes life easier for humans. – Rui F Ribeiro Feb 13 '18 at 12:35
  • @RuiFRibeiro, $ date +%s 1518530553 $ date -d \@1518530553 вівторок, 13 лютого 2018 16:02:33 +0200 – shcherbak Feb 13 '18 at 14:03
  • I am afraid I do not read Russian. I am not discussing the lack of merit of your technical solution, it is just that the format YYYYMMDDxx is more convenient for human operators when debugging problems, and is a more or less de facto unofficial standard. – Rui F Ribeiro Feb 13 '18 at 14:07
  • 2
    @RuiFRibeiro it is not trivial to be conform with YYYYMMDDxx standard in case of the Ansible (to much workarounds needed). by the way, it was ukrainian output (also cyrillic), not russian :) I'v just pointed the ```date -d @TIMESTAMP``` for converting to humanreadable date – shcherbak Feb 13 '18 at 19:35
0

A bash script searching for:

   12345 ; Serial

in directory /etc/bind/zones. It should match any number before ; Serial (case sensitive). And replace it with format YYYYMMDDxx.

#!/bin/bash

ZONES_PATH="/etc/bind/zones"
DATE=$(date +%Y%m%d)
# we're searching for line containing this comment
NEEDLE="Serial"
for ZONE in $(ls -1 $ZONES_PATH) ; do
    curr=$(/bin/grep -e "${NEEDLE}$" $ZONES_PATH/${ZONE} | /bin/sed -n "s/^\s*\([0-9]*\)\s*;\s*${NEEDLE}\s*/\1/p")
    # replace if current date is shorter (possibly using different format)
    if [ ${#curr} -lt ${#DATE} ]; then
      serial="${DATE}00"
    else
      prefix=${curr::-2}
      if [ "$DATE" -eq "$prefix" ]; then # same day
        num=${curr: -2} # last two digits from serial number
        num=$((10#$num + 1)) # force decimal representation, increment
        serial="${DATE}$(printf '%02d' $num )" # format for 2 digits
      else
        serial="${DATE}00" # just update date
      fi
    fi
    /bin/sed -i -e "s/^\(\s*\)[0-9]\{0,\}\(\s*;\s*${NEEDLE}\)$/\1${serial}\2/" ${ZONES_PATH}/${ZONE}
    echo "${ZONE}: "
    grep "; ${NEEDLE}$" $ZONES_PATH/${ZONE}
done

Modified version for bind configuration managed in a git repository, that update serial only for modified zone file:

#!/bin/bash
ZONES_PATH="$(pwd)/zones"
REPO_PATH="$(git rev-parse --show-toplevel)"
DATE=$(date +%Y%m%d)
NEEDLE="Serial"
for ZONE in $(git diff --name-only --diff-filter=AM `git merge-base origin/master HEAD` $ZONES_PATH) ; do
    curr=$(/bin/grep -e "${NEEDLE}$" ${REPO_PATH}/${ZONE} | /bin/sed -n "s/^\s*\([0-9]*\)\s*;\s*${NEEDLE}\s*/\1/p")
    if [ ${#curr} -lt ${#DATE} ]; then
      serial="${DATE}00"
    else
      prefix=${curr::-2}
      if [ "$DATE" -eq "$prefix" ]; then # same day
        num=${curr: -2} # last two digits from serial number
        num=$((10#$num + 1)) # force decimal representation, increment
        serial="${DATE}$(printf '%02d' $num )" # format for 2 digits
      else
        serial="${DATE}00" # just update date
      fi
    fi
    /bin/sed -i -e "s/^\(\s*\)[0-9]\{0,\}\(\s*;\s*${NEEDLE}\)$/\1${serial}\2/" ${REPO_PATH}/${ZONE}
    echo "${ZONE}: "
    grep "; ${NEEDLE}$" ${REPO_PATH}/${ZONE}
done

Note: you shouldn't make more than 99 modification during single day :)

Tombart
  • 2,630
  • 5
  • 26
  • 39
  • The only problem with this script is updating *all* serials. In servers with many zones, you might only want to update the zones that were modified since the last time you ran it. – Rui F Ribeiro Feb 13 '18 at 14:15
  • 1
    @RuiFRibeiro If you're versioning your configuration files with `git` you could replace `ls -1` with something like `git diff` that would find only changed files. – Tombart Feb 14 '18 at 07:15
  • @RuiFRibeiro I've added an example with `git diff` as it was hard to fit it into a single comment. – Tombart Feb 14 '18 at 12:56
0

@tombart answer works, this is just simpler and for a small lab environment where all zones are updated and are not under source control it's just easier.

#!/usr/bin/env bash

set -euo pipefail

: ${1?"Usage: $0 <zone file>"}

IFILE=$1

if [ ! -w "${IFILE}" ]; then
    echo "Error cannot write to ${IFILE}"
    exit
fi

if [ ! -w $(pwd) ]; then
    echo "Error, sed needs write permission for temp file, add w to current directory"
    exit
fi

PREV_SERIAL=$(grep -i Serial "${IFILE}" | awk '{print $1}')
TODAY=$(date +%Y%m%d00)

if [ "$PREV_SERIAL" -ge "${TODAY}" ]; then
    NEW_SERIAL=$((PREV_SERIAL+1))
else
    NEW_SERIAL=${TODAY}

fi
sed -i "s/${PREV_SERIAL}/${NEW_SERIAL}/" "${IFILE}"

printf "Zone: %s [%d -> %d]\n" "${IFILE}" "${PREV_SERIAL}" "${NEW_SERIAL}"
awm
  • 101
  • sed uses the local directory for a temp file, if you want to remove that requirement you can re-write that line with an awk < > .. – awm Sep 04 '22 at 00:20
0

Another answer referenced ansible. This approach fully works, zone configs are generated from templates and the serial is updated using simple expression in jinja2 template. The approach I'm using is that current zone file has the current value. Extract that and increment it.

- name: get current bind9 serial
  block:
    - ansible.builtin.slurp:
        path: "/etc/bind/zones/db.{{ vw_tld }}"
      register: bind9_current

    - ansible.builtin.set_fact:
        bind9_serial_concat: "{{ (bind9_current.content | b64decode | regex_search('[0-9]+[ ]+; Serial'))[0:10] }}"
  rescue:
    - ansible.builtin.set_fact:
        bind9_serial_concat: "1970010100"

- ansible.builtin.set_fact:
    bind9_serial_date: "{{ bind9_serial_concat[0:8] }}"
    bind9_serial_counter: "{{ bind9_serial_concat[8:10] }}"

- ansible.builtin.set_fact:
    bind9_serial_new: "{{ now(fmt= '%Y%m%d') }}{{ '%02d' | format(bind9_serial_counter | int + 1) }}"
  when: bind9_serial_date == now(fmt= "%Y%m%d")

- ansible.builtin.set_fact:
    bind9_serial_new: "{{ now(fmt= '%Y%m%d') }}00"
  when: bind9_serial_date != now(fmt= "%Y%m%d")

- name: bind9 database
  ansible.builtin.template:
    src: bind9.db.j2
    dest: "/etc/bind/zones/db.{{ vw_tld }}"

- name: bind9 reverse database
  ansible.builtin.template:
    src: bind9.db.reverse.j2
    dest: /etc/bind/zones/db.192.168

Rob Raymond
  • 101
  • 2