PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/dedrads/extras
Viewing File: /opt/dedrads/extras/zsu
#!/usr/bin/perl -i ( my $IDENT = '@(#)zsu: update DNS zone serial number' ) =~ s/^[^:]*: *//; =head1 NAME B<zsu> - update serial numbers in DNS zone files =head1 SYNOPSIS B<zsu> [B<-cdfhLnv>] I<zone> ... =head1 README B<zsu> updates serial numbers in DNS zone files. =head1 DESCRIPTION After any changes are made to a DNS zone file, the serial number must be increased -- otherwise changes will not propagate to the slave servers (secondaries). B<zsu> handles the serial number update automatically, while preserving everything else in the file. Forgetting to increase the serial number is one of the most common causes of hair loss among DNS administrators! =head2 Introduction B<zsu> expects one or more zonefile names as arguments. The command zsu /etc/db.local 0.0.127.in-add.arpa /var/named/db.example.com will update the serial numbers in each of the three zone files listed. B<zsu> is most commonly used as part of a revision control system for zone files, just before changes are committed to a repository. The following simple script demonstrates this. The script expects a single zonefile name as an argument, and relies on ci/co/rcsdiff (all parts of RCS, from F<ftp://ftp.cs.purdue.edu/pub/RCS/> ): #!/bin/sh co -l $1 vi $1 rcsdiff -q $1 > /dev/null if [ ! $? ]; then zsu -cf $1 ci -u $1 fi B<zsu> will ignore zone files where the originating host in the C<SOA> record does not match the local hostname. Use the B<-f> option to override this check. =head2 Details B<zsu> works with the standard C<YYYYMMDDN> serial number format, which is derived from the current date and a counter to distinguish multiple changes made the same day. B<zsu> tries very hard to increase the serial number while keeping its format. B<zsu> works with 2 or 4 digit years and 1 or 2 digit counters, so it will also try to work with formats C<YYMMDDN>, C<YYYYMMDDNN> and C<YYMMDDNN>. Unless the B<-n> option is given, B<zsu> will only process zone files with serial numbers in such formats; other zone files will be skipped. Unsupported formats include YYYYMMDDmm, where mm is time since midnight expressed in 15-minute units, or good old NNNN flat integer counters. I could add support for YYYYMMDDmm if there is demand. Often NNNN format counters are used with some kind of DNS management system, and most such systems want to manage the serial numbers themselves, but when you know it is safe to do so, the B<-n> option can be specified to force B<zsu> to treat all serial numbers as plain integers. B<zsu> understands standard zonefile syntax and will attempt to change the first SOA record found in each of the zones specified. B<zsu> will silently ignore zone files which do not appear to be for the local host to prevent changes to zone files on slave servers. Use the B<-f> option to force updates even if the origin in the SOA record fails to match the hostname as determined by B<zsu>. When the serial number indicates a date in the future, B<zsu> will continue to use the future date, as long as the counter can still be incremented while retaining the date format. In verbose mode, a warning is issued when encountering such a timewarp. In a future release, serial number wraparound (see RFC 1982) may be supported to help fix inadvertent timewarps. Use the B<-c> option to allow B<zsu> to change the format when necessary (by default B<zsu> will just complain about these situations). Changing the format is necessary if using two-digit years and the century has changed, or if YYMMDDNN format is used and NN is 99, or if a 1 digit counter has reached 9. Specify both B<-c> and B<-n> to convert from plain integer to date format serial numbers. You should only need to use B<-cn> once if you are upgrading to date format serial numbers; subsequent invocations should not specify either B<-c> or B<-n>. =head1 OPTIONS =over 6 =item B<-c> Change serial number format if necessary (otherwise will simply warn about overflow and similar errors, and leave the zone file intact). In conjunction with the B<-c> option, convert integer serial numbers to YYYYMMDDN format. Do not use B<-c> if other programs rely on the serial format! =item B<-d> Print debugging information. =item B<-f> Force update, even if this host is not SOA origin. =item B<-h> Display a brief help message. =item B<-L> Show the software license. =item B<-n> Treat the serial number as a plain integer, and increment it. Take care with this option if zone files are generated automatically, for instance from a database! =item B<-v> Verbose mode. Show the progress of the program. =back =head1 RETURN VALUE Returns 0 on success, -1 if there was a problem with the command line arguments, or a positive integer indicating the number of zone files which could not be updated. =head1 PREREQUISITES You need Perl installed. See F<http://www.perl.org/> for details. Latest versions have been tested with perl 5.005_03 but should also work with other 5.x versions (including 5.6.1). Versions up to 1.18 were compatible with perl 4, but later versions require perl 5. =head1 EXAMPLES The first few lines of a zone file will typically look something like: ; some comments @ IN SOA myhost.example.com. hostmaster.example.com. ( 1998021503 ; the serial number 28800 ; refresh If the system date was 12 August 2001 and you updated the zone with B<zsu>, this snippet would end up as: ; some comments @ IN SOA myhost.example.com. hostmaster.example.com. ( 2001081200 ; the serial number 28800 ; refresh Here is a table of what would be done to some other serial numbers, if the system date was 12 August 2001: original zsu zsu -c ----------- ---------------- ---------------- 9712231 9712232 9712232 97122301 97122302 97122302 199712231 199712232 199712232 1997122301 1997122302 1997122302 9712239 warn: no change 200108120 97122399 warn: no change 2001081200 199712239 warn: no change 200108120 1997122399 warn: no change 2001081200 0108129 warn: no change 01081210 01081299 warn: no change 2001081200 200108129 warn: no change 2001081210 2001081299 warn: no change warn: no change original zsu -cn zsu -n ----------- ---------------- ---------------- 837 200108120 838 203456789 2001081200 203456790 1034567890 2001081200 1034567891 2147483646 warn: no change 2147483647 2147483647 warn: no change warn: no change =head1 BUGS The hostname checking in B<zsu> is known to be buggy; for instance it will fail to produce a warning if it needs a domain name, but domainname returns just whitespace. Please report other programming errors to me. =head1 SEE ALSO named(8) =head1 AUTHOR Copyright 1994-2004 Andras Salamon C<E<lt>andras@dns.netE<gt>>. =head1 HISTORY Version 1.20 added more information about the -n option. Version 1.19 now requires Perl 5, added -n option, changed warnings to use NN instead of nn and (YY)YY instead of (yy)yy. Version 1.18 supports dates in the future. Version 1.17 moved to POD documentation. Version 1.16 renamed the F<README.zsu> file to F<README>, and fixed the availability information. Version 1.15 fixed handling of C<SOA> records where the serial is on the same line as the C<SOA> tag. Thanks to Frederic Marchand for picking up the problem and suggesting a solution. Single line C<SOA> records now also don't require parentheses, as per RFC 1034. Version 1.14 added documentation fixes, moved the distribution location, and noted where to get B<zsu> in the documentation. Version 1.13 fixed various problems with 2-digit year and 1-digit counter formats. B<zsu> is now able to change the format when appropriate, ie. when the century has changed, or if C<YYMMDDNN> format is used and C<NN> is 99, or if a 1 digit counter has reached 9. This version introduced the B<-c> option; previously the serial number format was silently changed when necessary. Use B<-c> for the old behaviour. =head1 AVAILABILITY The latest version of B<zsu> is available from F<http://www.dns.net/dist/zsu/> and also from I<CPAN>, at F<http://www.cpan.org/authors/id/A/AZ/AZS/zsu/> and in F<http://www.cpan.org/scripts/Networking/> . =head1 SCRIPT CATEGORIES Networking VersionControl/CVS Unix/System_administration =cut # internal variables #--------------------------------- ( my $BCMD = $0 ) =~ s/.*\///; ( my $REVISION ) = ( '$Revision: 1.20 $' =~ /[^\d\.]*([\d\.]*)/ ); my $HELPSTRING = "For help, type: $BCMD -h"; my $USAGE = "Usage: $BCMD [-cdfhLv] zone ..."; my $exitcode = 0; # parse command line arguments #----------------------------- use Getopt::Std; use vars qw( $opt_c $opt_d $opt_f $opt_h $opt_L $opt_n $opt_v ); use strict; if (! &getopts('cdfhLnv')) { print STDERR "$USAGE\n$HELPSTRING\n"; exit -1; } if ( $opt_h ) { print <<EOT; $BCMD $REVISION: $IDENT $USAGE Update serial number of DNS zone file using (YY)YYMMDDN(N) format convention. -c change serial number format if necessary -d print debugging information -f force update, even if this host is not SOA origin -L display software license -n treat serial number as a plain integer -v turn on verbose mode zone ... DNS zone files to update Default is to preserve the serial format and issue warnings when trying to update (YY)YYMMDD9 or if 99MMDDN(N) was last century. Use -c to allow format changes in these situations instead. Do not use -c if other programs rely on the serial format! Specify -cn to convert from NNNN style serial numbers to YYYYMMDDN. Zones are skipped if the SOA origin does not match the local hostname; use -f to force updates regardless. EOT exit 0; } elsif ( $opt_L ) { print <<EOT; Copyright 1994-2004 Andras Salamon <andras\@dns.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. If you do not already have a copy of the GNU General Public License, you can obtain a copy by anonymous ftp from prep.ai.mit.edu (file COPYING in directory /pub/gnu) or write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EOT exit 0; } my $DEBUG = $opt_d; my $VERBOSE = $opt_v || $DEBUG; if ( @ARGV < 1 ) { print STDERR "$USAGE\n$HELPSTRING\n"; exit -1; } # Set up fully qualified host name #--------------------------------- # zone files must have originating host fully qualified, since information # from outside zone may be necessary to understand non-FQ domain names my ( $myhost, $mydom ); if ( ! $opt_f ) { ( $myhost = `hostname` || `uname -n` ) =~ s/\s*$//; if ( $myhost !~ /\./ ) { if ( ! ( $mydom = `domainname` ) ) { warn "cannot get FQDN of host" if $VERBOSE; } else { if ( $mydom !~ /^\./ ) { $mydom = ".$mydom"; } $myhost .= $mydom; } } if ( $myhost !~ /\.$/ ) { $myhost .= '.'; } } # warn about converting N to NN format #---------------------------------- sub bump { my $o_count = shift; warn "$ARGV: converting to NN format serial" if $VERBOSE && $o_count eq '9' && $opt_c; $o_count + 1; } # generate a sensible serial number, based on the existing one # # try to use today's date as returned by ctime(3) # update count if serial has today's date already # preserve YY format if used # needs to detect RFC 1982 2^31 hack! #---------------------------------- sub generate_new { my $o_serial = shift; my ( $mday, $mon, $year ) = ( localtime( time ) )[3..5]; $mon ++; # change 0..11 to 1..12 $year += 1900 if $year < 1000; # fix 1900-offset years printf STDERR "local date: %04d/%02d/%02d\n", $year, $mon, $mday if $DEBUG; # default is to generate new YYYY format date with 0 counter my $n_y = $year % 100; my $n_c = ( $year - $n_y ) / 100; my $n_date = sprintf "%02d%02d%02d", $n_y, $mon, $mday; my $n_serial = $o_serial; # numeric format if ( $opt_n ) { if ( $opt_c ) { # change to YYYYMMDDN format $n_serial = sprintf "%s%06d0", $n_c, $n_date; if ( $n_serial <= $o_serial ) { # try ...NN format $n_serial .= '0'; if ( $n_serial le $o_serial ) { warn "$ARGV: cannot convert $o_serial to YYYYMMDDNN format, leaving as is"; $n_serial = $o_serial; $exitcode ++; } } } else { # keep numeric format, just increment if ( $o_serial eq '2147483647' ) { # avoid integer overflow warn "$ARGV: cannot increment $o_serial, leaving as is"; $exitcode ++; } else { $n_serial = $o_serial + 1; my $len = length $o_serial; $len = length $n_serial if $len < length $n_serial; $n_serial = sprintf "%0*d", $len, $n_serial; } } return $n_serial; } $n_serial = $o_serial; # note assumption that years are in range [1900, 2199] my ( $o_c, $o_y, $o_m, $o_d, $o_count ) = ( $o_serial =~ /^(19|20|21)?(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])(\d\d?)$/ ); unless ( defined $o_y && defined $o_m && defined $o_d && defined $o_count ) { warn "$ARGV: serial $o_serial does not match heuristics, leaving as is"; $exitcode ++; } else { my $o_date = $o_y.$o_m.$o_d; $o_c = '' unless defined $o_c; my $n_count = 0; # two cases: check if counter can be bumped, if necessary if ( ( $o_count =~ /\d\d/ && $o_count < 99 ) || ( $o_count =~ /^\d$/ && ( $o_count < 9 || $opt_c ) ) ) { print STDERR "can bump serial\n" if $DEBUG; # try to keep YY format dates, if currently being used if ( $o_c eq '' ) { print STDERR "currently using YY format dates\n" if $DEBUG; if ( $n_date > $o_date ) { print STDERR "keeping YY format\n" if $DEBUG; $n_c = $o_c; } elsif ( $n_date == $o_date ) { print STDERR "keeping YY format, bumping count\n" if $DEBUG; ( $n_c, $n_count ) = ( $o_c, bump( $o_count ) ); } else { if ( $opt_c ) { warn "$ARGV: converting to YYYY format serial" if $VERBOSE; } else { warn "$ARGV: need -c to convert $o_serial to YYYY format, leaving as is"; ( $n_c, $n_date, $n_count ) = ( $o_c, $o_date, $o_count ); $exitcode ++; } } } else { # already using YYYY format if ( $n_c.$n_date < $o_c.$o_date ) { # should use 2^31 hack here, see RFC 1982 # for now, keep future date and bump count warn "$ARGV: serial $o_serial is in future, processing" if $VERBOSE; print STDERR "$n_c,$n_date vs. $o_c,$o_date\n" if $DEBUG; ( $n_c, $n_date, $n_count ) = ( $o_c, $o_date, bump( $o_count ) ); } elsif ( $n_c.$n_date == $o_c.$o_date ) { print STDERR "YYYY format, bumping count\n" if $DEBUG; $n_count = bump( $o_count ); } # else use YYYY format } } else { # can't bump counter if ( $n_c.$n_date <= $o_c.$o_date ) { # problem: out of counts and zone date is too new # should use 2^31 hack if new < old, see RFC 1982 warn "$ARGV: cannot increment $o_serial, leaving as is"; ( $n_c, $n_date, $n_count ) = ( $o_c, $o_date, $o_count ); $exitcode ++; } # else use YYYY format } $n_serial = sprintf "%s%06d%0*d", $n_c, $n_date, ( ( $o_count =~ /^\d$/ ) ? 1 : 2 ), $n_count; } print STDERR "New serial: $n_serial\n" if $DEBUG; $n_serial; } # now parse zone file #-------------------- # state table: 0 looking for SOA # 1 found SOA, looking for serial # 2 found serial, looking for next file my $state = 0; while ( <> ) { if ( $state == 0 ) { # ... SOA zone_origin zone_contact ( serial ... # ^ $1 ^ $2 ^ $3 ^ $4 ^ $5 # $4 will be '' if serial is on subsequent line, see state1 if ( /^([^;]*\bSOA\b\s+)([^\s;]+)(\s+[^\s;]+\s+\(?\s*)([^\s;]*)(.*)/i ) { my $ours = 0; if ( $opt_f || ( $2 eq $myhost ) ) { $ours = 1; } else { $state = 2; } if ( $ours ) { if ( "$4" ne '' ) { my $before_serial = $1 . $2 . $3; my $o_serial = $4; my $after_serial = $5; if ( $o_serial !~ /^[\d.]+$/ ) { warn "$ARGV: cannot parse serial number, skipping" if $VERBOSE; $ours = 0; $exitcode ++; } else { $_ = $before_serial . &generate_new( $o_serial ) . $after_serial . "\n"; print STDERR "--> $_ <--\n" if $DEBUG; } $state = 2; } else { $state = 1; } } else { # not ours, don't change warn "$ARGV: origin non-local, skipping" if $VERBOSE; } } } elsif ( $state == 1 ) { if ( ! /^\s*;/ ) { # not commented, so serial should be here if ( /^(\s*)([0-9.]+)(.*)/ ) { $_ = $1 . &generate_new( $2 ) ."$3\n"; $state = 2; print STDERR "--> $_ <--\n" if $DEBUG; } else { warn "$ARGV: cannot parse SOA record, skipping" if $VERBOSE; $exitcode ++; } } # skip comment lines between `(' and serial } elsif ( $state == 2 ) { $state = 0 if eof; } else { die "internal error: state $state, quitting"; } } continue { print; } if ( $state == 2 ) { warn "internal error: did not detect end of last file" if $VERBOSE; $exitcode ++; } elsif ( $state == 1 ) { warn "$ARGV: could not locate serial number, skipping" if $VERBOSE; $exitcode ++; } exit $exitcode; # $Log: zsu,v $ # Revision 1.20 2004/08/08 18:24:24 andras # clarified documentation, esp. for -n option # trimmed log since revisions already in pod # # Revision 1.19 2004/08/04 20:43:21 andras # added -n option # updated warning text # strict variables # fixed verbose/debug interaction #