Contrary to its name, the ISC DHCP lease file may contain other
information, in addition to the leases. This information will not be
migrated to the Kea lease file.
Example files
Several files were added to examples/ directory. These are:
- example1-dhcp4.conf - config file for ISC DHCP. This is not really needed,
except perhaps it's useful to generate more data.
- example1-dhcp4.leases - this file contains lease information. This is the
input file.
- example1-kea-leases4.csv - this is the converted (output) file.
- example1-kea4.conf - this is an example kea config file that allows
starting Kea and loading the .csv file.
The conversion was done by hand and may contain some mistakes.
Converter source code
dhcp2kea/ directory contains:
- dhcp2kea.py - converter source code written in Python3
- dhcp2kea.php - the driver for running the converter from a web-browser
with
simple user interface
- dhcp2kea.html - web interface for testing the converter with syntax
colored
items
- dhcp2kea.png - web interface screendump
Useful documentation
- On-line version of the dhcp.leases man page: https://kb.isc.org/docs/isc
-dhcp-41-manual-pages-dhcpdleases. The actual man page is available in dhcp
source code
dhcp2kea.php
<html>
<head>
<meta charset="UTF-8">
</head>
<script>
function conv()
{
convert( document.getElementById( 'ta' ).innerHTML
.replace( /<[^>]*>?/gm,''),document.getElementById('ta2'));
}
function k( e )
{
if ((e.ctrlKey || e.metaKey) )
{
if(e.keyCode == 19)
{
if( confirm("Save?") )
local
Storage["dhcp2kea"] = document.getElementById("ta").innerHTML;
}
if( e.keyCode == 18)
{
if(("dhcp2kea" in localStorage) && confirm("Restore?") )
document.getElementById( "ta" ).
innerHTML=localStorage["dhcp2kea"];
}
}
if( (e.ctrlKey || e.metaKey) && (e.keyCode == 13
|| e.keyCode == 10))
{
e.preventDefault();
conv();
// var e=document.getElementById("title");e.inne
rHTML=e.innerHTML.replace(/ \([\s\S]*?\)/g, '');
}
}
function tabulate( csv, p )
{
var ss = csv.split('\n');
var s = '<table style="text-align:center">';
for( var i=1;i<ss.length-1;i++)
{
s += i==1?'<tr style="color:white;background-color:#ee4
444;">':i%2==1?'<tr style="">':'<tr>';
var ss2= ss[i].split(',');
if(ss2.length>1) for(var j=0;j<ss2.length;j++)
{
s += (i==1?'<th>':'<td>') + ss2[j]
+ (i==1?'</th>':'</td>');
}
s += '</tr>';
}
p.innerHTML = s +'</table>';
}
function convert( s, ta2 )
{
var xhttp = new XMLHttpRequest();
xhttp.open( "POST", "dhcp2kea.php" , true);
xhttp.setRequestHeader( 'Content-type', 'application/x-www-form
-urlencoded');
xhttp.onload
= function()
{
ta2.innerHTML = xhttp.
responseText.split( '\n' ).slice( 1 ).join( '\n' );
tabulate( xhttp.responseText, document.getElementById( 'p' ));
};
xhttp.send( "ta=" + encodeURIComponent( s ) );
}
function colored( s )
{ // syntax coloring
var w = '(\nlease|starts|ends|hardware ethernet|client
-hostname| \\buid|\nia -na|\nia -pd|max -life|preferred
-life|iaaddr|set ddns -fwd -name =)';
s = s.replace( /(\>|\<)/gm, /* < > */
function( m )
{
return( "<span style='color:red'>"+(m=='>'?'>
':'<')+'</span>' );
} );
s = s.replace( new RegExp( w, "g")
, "<span style='color:blue'>$&</span>");
s = s.replace( /\/\/.*/g
, "<span style='color:gray'>$&</span>"); // comment
s = s.replace(/\/\*(.|\n)*?\*\//gm,"<span style='color:gray'&g
t;$&</span>"); //comment
s = s.replace(/"(.|\n)*?"/gm,
function( m )
{
return( "<span style='color:green'>"+m.replac
e(/<[^>]*>?/gm,'')+"</span>");
}
); //string
return( s );
}
function colored2( s, flag)
{ // syntax coloring, when flag is true with
line
numbering
var w = '(class|def |import)';
var w1 = '(self|len|range|join|replace)';
var w2 = '(for |if |in |try:|except:|else:|elif|return|print)';
// s = s.replace(/(\>|\<)/gm, /* < > */
// function( m )
// {
// return "<span style='color:red'>"+(m=='>'?
// '>':'<')+'</span>';});
s = s.replace( /\b(\d+)\b/gm
,"<span style='color:red'>$&</span>"); // number
s = s.replace( new RegExp(w,"g")
, "<span style='color:blue'>$&</span>");
s = s.replace( new RegExp( w1,"g"),"<span style='color:darkma
genta'>$&</span>");
s = s.replace( new RegExp( w2,"g"),"<span style='font-weight:
bold;'>$&</span>");
s = s.replace( /(#.*$)/gm,
function( m )
{
return("<span style='color:gray'>"+m.repla
ce(/<[^>]*>?/gm,'')+"</span>");
}) // python comment
// s = s.replace( /\/\/.*/g
// ,"<span style='color:gray'>$&</span>"); // C++
// comment
// s = s.replace(/\/\*(.|\n)*?\*\//gm,"<span style='color:gray'
// >$&</span>"); // C comment
// s = s.replace(/"(.|\n)*?"/gm
// ,"<span style='color:green'>$&</span>");
// string
// s = s.replace( /"""(.|\n)*?"""/gm,
// function( m )
// {
// return( "<span style='color:green'>"+m.replac
// e(/<[^>]*>?/gm,'')+"</span>");
// }
//); //string
s = s.replace( /"(.|\n)*?"/gm,
function( m )
{
return( "<span style='color:green'>"+m.replac
e(/<[^>]*>?/gm,'')+"</span>");
}
); //string
var ss = s.split('\n');
flag = flag || false;
if( flag )
{
s = '';
for( var i =0; i < ss.length; i++)
{ // make line numbers
s += '<span style="color:gray;border-right: thin solid gray;
">' + ("
" + (i+1)).slice(-4) + ' </span> '+ ss[i] + '\n';
}
}
return(s);
}
function readFile( file )
{
var f = new XMLHttpRequest();
f.open( "GET", file, false);
f.onreadystatechange = function ()
{
if( f.readyState === 4)
{
if(f.status === 200 || f.status == 0)
{
document.getElementById('ta').innerHTML
= colored( f.responseText);
document.getElementById( 'ta' ).focus();
}
}
}
f.send( null );
}
function readLocalFile( e )
{
var file = e.files[0];
if( !file )
{
return;
}
var reader = new FileReader();
reader.onload = function( e )
{
document.getElementById('ta').innerHTML = colored(e.target.result);
document.getElementById('ta').focus();
};
reader.readAsText( file );
}
function saveFile( ta, fname )
{
var text = ta.innerHTML.replace(/\n/g, "\r\n");
var blob = new Blob( [text], { type: "text/plain"});
var a = document.createElement("a");
a.download = fname;
a.href = window.URL.createObjectURL( blob );
a.target ="_blank";
a.style.display = "none";
document.body.appendChild( a );
a.click();
document.body.removeChild( a );
}
function html2md( s )
{
var html = s
.replace(/^\<h1\>(.*?)\<\/h1\>/gim,'# $1')
.replace(/^\<h2\>(.*?)\<\/h2\>/gim,'# $2')
.replace(/^\<h3\>(.*?)\<\/h3\>/gim,'# $3')
return( html );
}
function md2html( s )
{
var html = s
.replace(/^#### (.*$)/gim,'<h4 id="$1">$1</h4>')
.replace(/^### (.*$)/gim,'<h3 id="$1">$1</h3>')
.replace(/^## (.*$)/gim,'<h2>$1</h2>')
.replace(/^# (.*$)/gim,'<h1>$1</h1>')
.replace(/^\> (.*$)/gim,'<blockquote>$1</blockquote>')
.replace(/\*\*(.*)\*\*/gim,'<b>$1</b>')
.replace(/\*(.*)\*/gim,'<i>$1</i>')
.replace(/!\[(.*?)\]\((.*?)\)/gim,
"<br><br><center><img alt='$1'
src = '$2' width=720/></center>")
.replace( /\[(.*?)\]\((.*?)\)/gim,"<a href='$2'>$1</a>")
.replace( /\n\- (.*$)/gim,'\n<ul><li>$1</li></ul>')
.replace(/(\<\/ul\>\n(.*)\<ul\>*)+/gm,'\n')
.replace(/\n\d+\. (.*$)/gim,'\n<ol><li>$1</li></ol>')
.replace(/(\<\/ol\>\n(.*)\<ol\>*)+/gm,'\n')
// .replace(/\n$/gim,"<br />")
.replace( /```([\s\S]+?)```/gim,
function( m )
{
return '<pre><div wrap="off" style="margin-left:32;width:640;min
-height:128;max-height:420;-moz-appearance: textfield-multiline;
-webkit
-appearance: textarea;overflow:auto;resize: both;background
-color:#eeeeee">'
+colored2(html2md(m).replace(/```(.*)
+\n/gim,'').replace(/```$/gim,''),true)
+'</div></pre>';
}
)
return( html.trim() );
}
function f_onload()
{
var e = document.getElementById( "ta" );
e.innerHTML = colored( e.innerHTML );
var fname="dhcp2kea.md"
var f = new XMLHttpRequest();
f.open("GET", fname, false);
f.onreadystatechange = function ()
{
if( f.readyState === 4)
{
if( f.status === 200 || f.status == 0)
{
document.getElementById('md').innerHTML = md2html(f.responseText);
}
}
}
f.send( null );
}
</script>
<body onload='f_onload();'>
<center>
<h1 id="title">dhcp2kea</h1>
<table style="width:960px">
<tr>
<td style="width:480px">
<div style="color:white;background-color:#009900;width:480px;">
<input type="file" title="Load local lease file"
onchange="javascript:readLocalFile(this);" />
<button title="Load example 1" onclick="readFile('example1
-dhcpd4.leases')">1</button>
<button title="Load example 2" onclick="readFile('example2
-dhcpd6.leases')">2</button>
<button title="Load example 3" onclick="readFile('example3
-dhcpd6.leases')">3</button>
</div>
<!-- <textarea autofocus id="ta" name="ta" onkeypress="k(event);"
autofocus
style="width:480px;height:480px;font-family:courier;font
-size:14"><?=$src?></textarea>
-->
<pre style="margin:0;">
<div id="ta" contenteditable="true" onkeypress="k(event);"
style="width:476px;height:480px;border:1px solid #ccc;padding:2px;
font-size:14px;overflow:auto;
word-break: unset;word-wrap: unset;overflow-wrap: unset;
-webkit-hyphens: unset;-moz-hyphens: unset;-ms-hyphens:
unset;hyphens: unset;
background-color:white;text-align:left;
-moz-appearance: textfield-multiline;-webkit-appearance: textarea;
resize: both;
"># The format of this file is documented in the dhcpd.leases(5) manual
page.
# This lease file was written by isc-dhcp-4.4.2
# authoring-byte-order entry is generated, DO NOT DELETE
authoring-byte-order little-endian;
server-duid 00:01:00:01:28:f8:2c:53:08:00:27:c7:c6:20;
ia-na cc:bb:aa:00:00:03:00:01:31:32:33:34:35:36 {
cltt 2 2021/10/12 11:22:10;
iaaddr 3002::200 {
binding state active;
preferred-life 225;
max-life 360;
ends 2 2021/10/12 11:28:10;
set ddns-fwd-name = "toms.four.example.com";
set ddns-dhcid = "\000\002\001'\223`\344\240\350\230:[\264\220va3p
-\335R\253\233\215\354\315%\346\034_\351\206k\002\224";
set ddns-rev-name = "0.0.2.0.0.0.0.0.0.0.0.0.0.0
.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.3.ip6.arpa.";
}
}
server-duid 00:01:00:01:28:f8:2c:53:08:00:27:c7:c6:20;
ia-na cc:bb:aa:00:00:03:00:01:31:32:33:34:35:36 {
cltt 2 2021/10/12 11:22:10;
iaaddr 3002::200 {
binding state expired;
preferred-life 225;
max-life 360;
ends 2 2021/10/12 11:28:10;
}
}
</div>
</pre>
</td>
<td style="width:480px">
<div style="color:white;background-color:#0099cc;width:480px;">
<span style="position:relative;left:-20px;"><button title="Convert"
onclick="conv();">>></span></button>
<button style="float:right" title="Save to local disk"
onclick="saveFile(document.getElementById('ta2'),'a.csv')">Save</button>
</div>
<pre style="margin:0">
<div id="ta2" name="ta2"
style="width:476px;height:480px;border:1px solid #ccc;padding:2px;
font-size:14px;overflow:auto;background-color:white;text-align:left;
-moz-appearance: textfield-multiline;-webkit-appearance: textarea;
resize: both;
">
</div>
</pre>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td colspan=2">
<pre><div id="p" style="width:966px;overflow:auto;resize:both;-moz
-appearance:textfield-multiline;-webkit-appearance: textarea;"></div></pre>
</td>
</tr>
</table>
</center>
<hr>
<div id="md" style="width:960"></div>
</body></html>