<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Terry Burton's blog</title>
    <description>The weblog of Terry Burton, Leicester, UK</description>
    <link>https://blog.terryburton.co.uk</link>
    <atom:link href="https://blog.terryburton.co.uk/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Creating PDF Documentation From a GitHub Wiki Using Pandoc</title>
        <description>&lt;p&gt;The following explains how the &lt;a href=&quot;https://drive.google.com/viewerng/viewer?url=https://github.com/bwipp/postscriptbarcode/blob/master/docs/barcodewriter.pdf?raw=true&amp;amp;embedded=true&quot;&gt;printable documentation&lt;/a&gt; for &lt;a href=&quot;https://bwipp.terryburton.co.uk&quot;&gt;Barcode Writer in Pure PostScript&lt;/a&gt; was refreshed so that it could be generated primarily from content in the &lt;a href=&quot;https://github.com/bwipp/postscriptbarcode/wiki&quot;&gt;wiki&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;adding-the-wiki-as-a-git-submodule&quot;&gt;Adding the Wiki as a Git Submodule&lt;/h2&gt;

&lt;p&gt;To allow the documentation build system to access files in the wiki, build directory and main project repository using predictable relative file names you can add the wiki repository as a git submodule to the main repository:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git submodule add ../postscriptbarcode.wiki.git wikidocs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In future you will want to checkout your repository as follows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone --recursive git@github.com:bwipp/postscriptbarcode.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;documentation-build-system-file-structure&quot;&gt;Documentation Build System File Structure&lt;/h2&gt;

&lt;p&gt;We create the Pandoc-based documentation build system in the &lt;code class=&quot;highlighter-rouge&quot;&gt;__pandoc&lt;/code&gt; directory of the wikidocs submodule.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wikidocs
│
│ (Documentation build system)
│
├── __pandoc
│   │
│   ├── Makefile ①
│   │
│   │ (Symlink to wiki images directory)
│   │
│   ├── images -&amp;gt; ../images/
│   │
│   │ (Filters for pre-processing the wiki markdown)
│   │
│   ├── __rewritewikilinks.hs ②
│   ├── __rewritepngtoeps.hs ③
│   │
│   │ (PDF specific content — mainly section headings, introductions, etc.)
│   │
│   ├── __symbology-reference.md
│   ├── __options-reference.md
│   └── __knowledge-base.md
│
│ (Normal wiki content follows)
│
├── images
│   ├── ean13-1.eps   (EPS files purpose generated for PDF documentation)
│   └── ean13-1.png
│
├── symbologies
│   └── EAN-13.md
├── options
│   └── Text-Properties.md
└── kb
      └── FAQs.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;pandoc-arguments&quot;&gt;Pandoc Arguments&lt;/h2&gt;

&lt;p&gt;To build the PDF documentation we run Pandoc with as follow:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ pandoc

  --from=markdown_github
  --to=latex

  --filter __pandoc/__rewritewikilinks.hs ②
  --filter __pandoc/__rewritepngtoeps.hs ③

  -M title=&quot;Barcode Writer in Pure PostScript&quot;
  -M author=&quot;https://bwipp.terryburton.co.uk&quot;

  -V geometry:a4paper,margin=2cm

  --toc --toc-depth=2
  --chapters

  --output=__pandoc/barcodewriter.pdf

  [ followed by a list of *.md files ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that this requires Pandoc version 1.12 or later for filter support.&lt;/p&gt;

&lt;h2 id=&quot;makefile-&quot;&gt;Makefile ①&lt;/h2&gt;

&lt;p&gt;Using a makefile allows the documentation to be rebuilt and added to the main repository using the following commands:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd wikidocs
$ make -f __pandoc/Makefile
$ cp __pandoc/barcodewriter.pdf ../docs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PANDOC_DIR = __pandoc
PANDOC_TEMPLATE_LATEX = $(PANDOC_DIR)/templates/template.latex
EPS_IMAGES = $(wildcard images/*.eps)
PDF_DOCS  = $(PANDOC_DIR)/barcodewriter.pdf

define MD_FILES =
  ../README.md                            \
  kb/Quick-Guide.md                       \
  ../src/README.monolithic                \
  ../src/README.resource                  \
                                          \
  $(PANDOC_DIR)/__symbology-reference.md  \
  symbologies/EAN-13.md                   \
...
  $(PANDOC_DIR)/__options-reference.md    \
  options/Text-Properties.md              \
...
  $(PANDOC_DIR)/__knowledge-base.md       \
  kb/FAQs.md                              \
...
  ../cited-by.md
endef

$(PDF_DOCS): $(MD_FILES) $(EPS_IMAGES) $(PANDOC_TEMPLATE_LATEX) $(INTRO_FILE_LATEX)
    pandoc                                      \
  -f markdown_github -t latex                   \
  -F $(PANDOC_DIR)/__rewritewikilinks.hs        \
  -F $(PANDOC_DIR)/__rewritepngtoeps.hs         \
  -M title=&quot;Barcode Writer in Pure PostScript&quot;  \
  -M author=&quot;https://bwipp.terryburton.co.uk&quot;    \
  -V geometry:a4paper,margin=2cm                \
  --toc --toc-depth=2                           \
  --chapters                                    \
  -o $@                                         \
  $(MD_FILES)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;filter-rewritewikilinkshs-&quot;&gt;Filter: rewritewikilinks.hs ②&lt;/h2&gt;

&lt;p&gt;Rewrite relative links to other wiki pages to lowercase in-page style links maintaining existing in-page links and absolute website links, e.g. links to a &lt;code class=&quot;highlighter-rouge&quot;&gt;EAN-13&lt;/code&gt; wiki page would become a &lt;code class=&quot;highlighter-rouge&quot;&gt;#ean-13&lt;/code&gt; in-page link. Then ensure that each page begins with a heading named after the page such that these rewritten links map to the label for the corresponding heading thus maintaining a functioning navigation system in the final PDF document.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;#!/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runhaskell&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Text.Pandoc.JSON&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.Char&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toJSONFilter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Inline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'#'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'h'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'t'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'t'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;':'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http:&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'h'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'t'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'t'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'s'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;':'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https:&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toLower&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritewikilinks&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;filter-rewritepngtoepshs-&quot;&gt;Filter: rewritepngtoeps.hs ③&lt;/h2&gt;

&lt;p&gt;Rewrite sources for images from &lt;code class=&quot;highlighter-rouge&quot;&gt;.png&lt;/code&gt; file to the corresponding &lt;code class=&quot;highlighter-rouge&quot;&gt;.eps&lt;/code&gt; file. Obviously this requires you to create the EPS files in the first place. For barcodes this greatly improves the quality of the images in the PDF output by maintaining them in vector format. This might not be as important for other types of content.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;#!/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runhaskell&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Text.Pandoc.JSON&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.FilePath&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toJSONFilter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rewritepngtoeps&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;rewritepngtoeps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Inline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritepngtoeps&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rewritefile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritepngtoeps&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;rewritefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rewritefile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replaceExtension&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.eps&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Fri, 20 Feb 2015 00:00:00 +0000</pubDate>
        <link>https://blog.terryburton.co.uk/2015/02/20/Creating-PDF-Documentation-From-a-GitHub-Wiki-Using-Pandoc.html</link>
        <guid isPermaLink="true">https://blog.terryburton.co.uk/2015/02/20/Creating-PDF-Documentation-From-a-GitHub-Wiki-Using-Pandoc.html</guid>
      </item>
    
      <item>
        <title>NAT Filtering DNS With iptables/netfilter</title>
        <description>&lt;p&gt;Update: DNS Response Policy Zones (DNS RPZ) are now a much better solution to this problem.&lt;/p&gt;

&lt;p&gt;Recently I have been looking at approaches to containing the activity of the Conficker (Downup, Downadup, Kido) worm, in particular by focusing on blocking of initial DNS queries for its large set of rendezvous domains that it uses to update its executable.&lt;/p&gt;

&lt;p&gt;The existing techniques that I’ve read about involve creating nameservers that are authoritative for a huge list of zones, either themselves resolving or forwarding to distinct resolvers. But as anybody that has run BIND configured with a large set of authoritative zones will know, the resource requirements for such a configuration are excessive: high memory usage, long pauses during cache cleanup, slow startup times…&lt;/p&gt;

&lt;p&gt;So I derived an entirely different filtering technique that appears to work very well for blocking a set of over 100,000 domains, which has negligible resource requirements and which does not require reconfiguration of an existing resolver infrastructure.&lt;/p&gt;

&lt;p&gt;The essential principle is that both UDP and TCP versions of the protocol for DNS queries are trivial to proxy in a robust manner at layer 4, i.e. using only simple NAT, without any application awareness. In fact, this is how many commodity broadband routers function - they perform NAT on DNS packets destined to their LAN-side IP address to redirect them to an ISP’s resolvers and then relay the response back to the requester.&lt;/p&gt;

&lt;p&gt;This allows for the creation of an extremely lightweight set of DNS proxy servers that can be placed between some network whose hosts you wish to contain and your existing resolver infrastructure. These proxy servers may then be configured to perform content-based filtering of DNS requests by performing string matching at a specific offset within the DNS packets. Such a proxy server requires nothing more than low-spec hardware (or a modest virtual machine) and uses only the built in features of a vanilla Linux 2.6 kernel - no nameserver software required.&lt;/p&gt;

&lt;p&gt;What follows assumes a sound understanding Linux networking and iptables. The firewall snippets are in “iptables-restore” format. It is intended to provide comprehensive details of the approach I am using but does not consitute anything like a complete HOWTO.&lt;/p&gt;

&lt;p&gt;The following configures a NAT that will rewrite DNS packets destined to the &lt;code class=&quot;highlighter-rouge&quot;&gt;DNS_PROXY&lt;/code&gt; address to a set of &lt;code class=&quot;highlighter-rouge&quot;&gt;DNS_RESOLVER_{1,2,3}&lt;/code&gt; addresses following a round-robin policy.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;*mangle
:PREROUTING ACCEPT [0:0]
-A PREROUTING -d [DNS_PROXY] -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 0  -m state --state new -j CONNMARK --set-mark 1
-A PREROUTING -d [DNS_PROXY] -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 1  -m state --state new -j CONNMARK --set-mark 2
-A PREROUTING -d [DNS_PROXY] -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 2  -m state --state new -j CONNMARK --set-mark 3
-A PREROUTING -d [DNS_PROXY] -p tcp -m tcp --dport 53 -m statistic --mode random --probability 0.33 -m state --state new -j CONNMARK --set-mark 1
-A PREROUTING -d [DNS_PROXY] -p tcp -m tcp --dport 53 -m statistic --mode random --probability 0.5  -m state --state new -j CONNMARK --set-mark 2
-A PREROUTING -d [DNS_PROXY] -p tcp -m tcp --dport 53                                               -m state --state new -j CONNMARK --set-mark 3
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING  -m connmark --mark 1 -j DNAT --to-destination [DNS_RESOLVER_1]
-A PREROUTING  -m connmark --mark 2 -j DNAT --to-destination [DNS_RESOLVER_2]
-A PREROUTING  -m connmark --mark 3 -j DNAT --to-destination [DNS_RESOLVER_3]
-A POSTROUTING -m connmark --mark 1 -j SNAT --to-source [DNS_PROXY]
-A POSTROUTING -m connmark --mark 2 -j SNAT --to-source [DNS_PROXY]
-A POSTROUTING -m connmark --mark 3 -j SNAT --to-source [DNS_PROXY]
COMMIT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We want DNS packets that are queries, rather than responses, to be sent via the &lt;code class=&quot;highlighter-rouge&quot;&gt;DNSCHECK&lt;/code&gt; chain. Other DNS packets are passed unchecked whilst non-DNS protocols are blocked. We only accept DNS packets from a trusted &lt;code class=&quot;highlighter-rouge&quot;&gt;SRC_NET&lt;/code&gt; to avoid being an open resolver.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;*filter
:FORWARD ACCEPT [0:0]
-A FORWARD -s SRC_NET -p udp --dport 53 -m u32 --u32 &quot;0&amp;gt;&amp;gt;22&amp;amp;0x3C@8&amp;gt;&amp;gt;15&amp;amp;0x01=0&quot; -j DNSCHECK
-A FORWARD -s SRC_NET -p udp --dport 53 -j ACCEPT
-A FORWARD -s SRC_NET -p tcp --dport 53 -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -j LOGDROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To reduce the number of (expensive) “string” match tests applied to each DNS query we dispatch the packet to the relevant &lt;code class=&quot;highlighter-rouge&quot;&gt;DNSCHECKxx&lt;/code&gt; chain based on the first two characters of the query data, using a (cheap) “u32” match on the correct offset of the packet.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;:DNSCHECK - [0:0]
-A DNSCHECK -m u32 --u32 &quot;0&amp;gt;&amp;gt;22&amp;amp;0x3C@19&amp;amp;0xffff=0x6161&quot; -j DNSCHECKaa
-A DNSCHECK -m u32 --u32 &quot;0&amp;gt;&amp;gt;22&amp;amp;0x3C@19&amp;amp;0xffff=0x6162&quot; -j DNSCHECKab
...
-A DNSCHECK -m u32 --u32 &quot;0&amp;gt;&amp;gt;22&amp;amp;0x3C@19&amp;amp;0xffff=0x7a7a&quot; -j DNSCHECKzz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In each &lt;code class=&quot;highlighter-rouge&quot;&gt;DNSCHECKxx&lt;/code&gt; chain we perform the full string matches on the query data.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;:DNSCHECKaa - [0:0]
-A DNSCHECKaa -m string --from 40 --to 53 --hex-string &quot;|08|aaadokfn|03|net|00|&quot;   --algo bm -j LOGDROP
-A DNSCHECKaa -m string --from 40 --to 49 --hex-string &quot;|05|aaakp|02|cc|00|&quot;       --algo bm -j LOGDROP
-A DNSCHECKaa -m string --from 40 --to 55 --hex-string &quot;|0b|aaapcxqiqgg|02|ws|00|&quot; --algo bm -j LOGDROP
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Log and drop matches, rate limiting to prevent flooding of logfiles.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;:LOGDROP - [0:0]
-A LOGDROP -m limit --limit 1/second --limit-burst 100 -j LOG
-A LOGDROP -j DROP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following sample scripts should be useful for generating and loading the daily iptables rulesets:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/terryburton/cf7e8504e18f4a9c803b&quot;&gt;gen_domains.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uses Downatool2 under Wine to create date-based files for a number of days that contain a sorted list of rendezvous domains for each Conficker variant. Could be invoked as an unprivileged user from cron once per week.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/terryburton/251ce9822fa0bc555683&quot;&gt;build_iptables.pl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Builds a iptables firewall policy in “iptables-restore” format that implements the NAT-filter for DNS described above from a list of files containing blacklisted domains.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/terryburton/6893f11c339d5bbd2f28&quot;&gt;load_iptables.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uses &lt;code class=&quot;highlighter-rouge&quot;&gt;build_iptables.pl&lt;/code&gt; to create a firewall policy to filter domains for the next couple of days and then executes it. Could be invoked as root from cron each night.&lt;/p&gt;
</description>
        <pubDate>Tue, 17 Nov 2009 00:00:00 +0000</pubDate>
        <link>https://blog.terryburton.co.uk/2009/11/17/NAT-Filtering-DNS-With-iptables-netfilter.html</link>
        <guid isPermaLink="true">https://blog.terryburton.co.uk/2009/11/17/NAT-Filtering-DNS-With-iptables-netfilter.html</guid>
      </item>
    
      <item>
        <title>Apache accesslog to syslog</title>
        <description>&lt;p&gt;Apache allows its error logs to be written to local syslog, however it does not natively support the directing of access logs to the syslog. How frustrating!&lt;/p&gt;

&lt;p&gt;It does however allow access logs to be written to a pipe and I have seen a number of home-brew scripts that essentially redirect the Apache access log data from STDIN to syslog.&lt;/p&gt;

&lt;p&gt;I’ve yet to see anything quite as simple as the following directive that I cooked up today:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CustomLog &quot;||/usr/bin/logger -t apache -i -p local6.notice&quot; combined
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It pipes the access log data to the BSD logger(1) utility that is installed by default on almost any Unix system. No need for any more of those STDIN wrapper scripts!&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Nov 2007 00:00:00 +0000</pubDate>
        <link>https://blog.terryburton.co.uk/2007/11/09/Apache-accesslog-to-syslog.html</link>
        <guid isPermaLink="true">https://blog.terryburton.co.uk/2007/11/09/Apache-accesslog-to-syslog.html</guid>
      </item>
    
  </channel>
</rss>
