{"id":272,"date":"2014-08-23T20:54:40","date_gmt":"2014-08-23T18:54:40","guid":{"rendered":"\/wordpress\/?p=272"},"modified":"2014-08-23T20:56:10","modified_gmt":"2014-08-23T18:56:10","slug":"setting-up-a-highly-available-ha-dns-in-freebsd-10","status":"publish","type":"post","link":"\/wordpress\/freebsd\/setting-up-a-highly-available-ha-dns-in-freebsd-10\/","title":{"rendered":"Setting up a highly available (HA) DNS in FreeBSD 10"},"content":{"rendered":"<p>In <a title=\"Setting up HAST through CARP\" href=\"\/wordpress\/freebsd\/setting-up-hast-through-carp\/\">Setting up HAST through CARP<\/a> preparations were done for making the same storage volume be able to be accessed through a redundant IP-address. Now comes the time to tie this together with an actual application and make the failover automatic. <a href=\"\/wordpress\/wp-content\/uploads\/2014\/03\/hast-with-carp.jpg\"><img loading=\"lazy\" src=\"\/wordpress\/wp-content\/uploads\/2014\/03\/hast-with-carp-300x292.jpg\" alt=\"hast with carp\" width=\"300\" height=\"292\" class=\"alignright size-medium wp-image-274\" srcset=\"\/wordpress\/wp-content\/uploads\/2014\/03\/hast-with-carp-300x292.jpg 300w, \/wordpress\/wp-content\/uploads\/2014\/03\/hast-with-carp.jpg 372w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>To the right is a graphical representation of all components tied together. In the middle there will be a DNS server that is either active on <code><strong>hast-a<\/strong><\/code> or <code><strong>hast-b<\/strong><\/code>, always through the common name <code><strong>hast-v<\/strong><\/code>. This can be applied to any simple network daemon that needs to be highly available.<\/p>\n<p>In the previous post hast was setup but not with automatic failover. We&#8217;ll use the device state change daemon <a href=\"http:\/\/man.freebsd.org\/devd\/8\">devd(8)<\/a> to catch when the carp interface changes state. As CARP has changed in FreeBSD 10, so has the necessary bits in devd. Add the following to <code>\/etc\/devd.conf<\/code><\/p>\n<pre><code># The below is valid configuration for FreeBSD 9 and earlier.\r\n# notify 0 {\r\n#        match \"system\"          \"IFNET\";\r\n#        match \"type\"            \"LINK_*\";\r\n#        match \"subsystem\"       \"carp*\";\r\n#        action \"\/root\/carpcontrol.sh $type $subsystem\";\r\n#};\r\n\r\n# The below is valid configuration for FreeBSD 10 and later.\r\nnotify 0 {\r\n        match \"system\"          \"CARP\";\r\n        match \"subsystem\"       \"[0-9]+@[0-9a-z]+\";\r\n        match \"type\"            \"(INIT|MASTER|BACKUP)\";\r\n        action \"\/root\/carpcontrol.sh $type $subsystem\";\r\n};\r\n<\/code><\/pre>\n<p>CARP has changed quite a lot in FreeBSD 10. This is how it&#8217;s setup nowadays. <em>(For FreeBSD 9 and earlier, refer to the previous post linked above.)<\/em><\/p>\n<h3>\/etc\/rc.conf on hast-a<\/h3>\n<pre><code>ifconfig_vmx0=\"inet 192.168.0.197\/24\"\r\nifconfig_vmx0_alias0=\"inet 192.168.0.199\/24 vhid 199 pass hastpass\"\r\nifconfig_vmx1=\"inet 192.168.100.197\/24\"\r\nifconfig_vmx1_alias0=\"inet 192.168.100.199\/24 vhid 199 pass hastpass\"\r\nifconfig_vmx2=\"inet 192.168.50.1\/30\"\r\npf_enable=\"YES\"\r\npf_rules=\"\/etc\/pf.conf\"\r\npf_flags=\"\"\r\npflog_enable=\"YES\"\r\npflog_logfile=\"\/var\/log\/pflog\"\r\npflog_flags=\"\"\r\npfsync_enable=\"YES\"\r\npfsync_syncdev=\"vmx2\"\r\n<\/code><\/pre>\n<h3>\/etc\/rc.conf on hast-b<\/h3>\n<pre><code>ifconfig_vmx0=\"inet 192.168.0.198\/24\"\r\nifconfig_vmx0_alias0=\"inet 192.168.0.199\/24 vhid 199 pass hastpass advskew 100\"\r\nifconfig_vmx1=\"inet 192.168.100.198\/24\"\r\nifconfig_vmx1_alias0=\"inet 192.168.100.199\/24 vhid 199 pass hastpass advskew 100\"\r\nifconfig_vmx2=\"inet 192.168.50.2\/30\"\r\npf_enable=\"YES\"\r\npf_rules=\"\/etc\/pf.conf\"\r\npf_flags=\"\"\r\npflog_enable=\"YES\"\r\npflog_logfile=\"\/var\/log\/pflog\"\r\npflog_flags=\"\"\r\npfsync_enable=\"YES\"\r\npfsync_syncdev=\"vmx2\"\r\n<\/code><\/pre>\n<h3>Minimal \/etc\/pf.conf<\/h3>\n<pre><code>prod_if = \"vmx0\"\r\nhast_if = \"vmx1\"\r\npfsync_if = \"vmx2\"\r\nprod_carp_ip = \"192.168.0.199\"\r\n\r\nset block-policy drop\r\nset skip on lo0\r\nset skip on pfsync0\r\n\r\nscrub in\r\n\r\npass quick on $pfsync_if proto pfsync keep state (no-sync)\r\npass quick proto carp keep state (no-sync)\r\n\r\nantispoof for $prod_if\r\nantispoof for $hast_if\r\n\r\npass in quick proto { tcp, udp } from any to $prod_carp_ip port = 53\r\nblock in quick proto { tcp, udp } from any to $prod_if port = 53\r\n\r\npass out quick on $prod_if from any to any keep state\r\npass out quick on $hast_if from any to any keep state\r\n<\/code><\/pre>\n<h3>\/root\/carpcontrol.sh<\/h3>\n<p>This is where the magic happens.<\/p>\n<pre><code>#!\/bin\/sh\r\n#\r\n# magnus.strahlert @ 140714\r\n#   script to handle hast failover\r\n\r\n_type=$1\r\n_subsyst=$2\r\n\r\nbn=${0##*\/}\r\nlogger=\/usr\/bin\/logger\r\nhastctl=\/sbin\/hastctl\r\njot=\/usr\/bin\/jot\r\nfsck=\/sbin\/fsck\r\n\r\n# Configurable variables below\r\nhast_dev=\/dev\/hast\/hast0\r\nhast_if=vmx1\r\nmp=\/usr\/local\/hast\r\n\r\n# What daemons to stop\/start when failover takes place.\r\ndaemons=\"named\"\r\n\r\nlogit() {\r\n  ${logger} -p \"$1\" -t ${bn} \"$2\"\r\n}\r\n\r\nif [ \"`echo ${_subsyst}|cut -d '@' -f2`\" != \"${hast_if}\" ]; then\r\n  logit kern.warning \"Ignoring change to ${_type} on non-hast if ${_subsyst}\"\r\n  exit\r\nfi\r\n\r\ncase ${_type} in\r\n  \"MASTER\")\r\n    logit kern.warning \"Caught ${_type} from ${_subsyst}\"\r\n\r\n    ${hastctl} role primary ${hast_dev##*\/}\r\n    if [ $? -ne 0 ]; then\r\n      logit kern.crit \"Unable to change role to primary\"\r\n      exit 1\r\n    fi\r\n\r\n    for i in `${jot} 30`; do\r\n      [ -c ${hast_dev} ] && break\r\n      sleep 1\r\n    done\r\n\r\n    if [ ! -c ${hast_dev} ]; then\r\n      logit kern.crit \"Timeout waiting for device ${hast_dev}\"\r\n      ${hastctl} role secondary ${hast_dev##*\/}\r\n      exit 1\r\n    fi\r\n\r\n    logit kern.warning \"HAST role changed to primary\"\r\n\r\n    logit kern.warning \"Running fsck on ${hast_dev}\"\r\n    ${fsck} -y -t ufs ${hast_dev}\r\n\r\n    if [ ! -d ${mp} ]; then\r\n      mkdir -p ${mp}\r\n    fi\r\n\r\n    logit kern.warning \"Mounting ${hast_dev}\"\r\n    mount -t ufs ${hast_dev} ${mp}\r\n\r\n    for d in ${daemons}; do\r\n      logit kern.warning \"Starting ${d} in master-mode\"\r\n      service $d onestart\r\n    done\r\n  ;;\r\n\r\n  \"BACKUP\")\r\n    logit kern.warning \"Caught ${_type} from ${_subsyst}\"\r\n\r\n    for d in ${daemons}; do\r\n      service $d onestop\r\n    done\r\n\r\n    logit kern.warning \"Unmounting ${hast_dev}\"\r\n    umount -f ${mp}\r\n\r\n    ${hastctl} role secondary ${hast_dev##*\/}\r\n\r\n    if [ $? -ne 0 ]; then\r\n      logit kern.crit \"Unable to change role to secondary\"\r\n      exit 1\r\n    fi\r\n\r\n    logit kern.warning \"HAST role changed to secondary\"\r\n  ;;\r\nesac\r\n<\/code><\/pre>\n<p>All files mentioned above need of course to exist on both servers.<\/p>\n<p>Daemons specified in the above script to be part of failover need to have their configuration saved on the hast volume. That might involve specifying specific rc-variables in \/etc\/rc.conf to point where the configuration files lies.<\/p>\n<h3>\/etc\/rc.conf<\/h3>\n<pre><code>named_conf=\"\/usr\/local\/hast\/etc\/namedb\/named.conf\"\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In Setting up HAST through CARP preparations were done for making the same storage volume be able to be accessed through a redundant IP-address. Now comes the time to tie this together with an actual application and make the failover automatic. To the right is a graphical representation of all components tied together. In the <span class=\"ellipsis\">&hellip;<\/span> <span class=\"more-link-wrap\"><a href=\"\/wordpress\/freebsd\/setting-up-a-highly-available-ha-dns-in-freebsd-10\/\" class=\"more-link\"><span>Read More &rarr;<\/span><\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[14,32],"tags":[44,31,43,34],"_links":{"self":[{"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/posts\/272"}],"collection":[{"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/comments?post=272"}],"version-history":[{"count":8,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/posts\/272\/revisions"}],"predecessor-version":[{"id":289,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/posts\/272\/revisions\/289"}],"wp:attachment":[{"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/media?parent=272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/categories?post=272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wp.strahlert.net\/wordpress\/wp-json\/wp\/v2\/tags?post=272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}