334 lines
11 KiB
Tcl
334 lines
11 KiB
Tcl
#
|
|
# Copyright 2012 the Boeing Company.
|
|
# See the LICENSE file included in this distribution.
|
|
#
|
|
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
#
|
|
# This is a separate "addons" file because it is closely tied to Python
|
|
# service definition for the IPsec service.
|
|
#
|
|
|
|
#
|
|
# Helper dialog for configuring the IPsec service
|
|
#
|
|
proc popupServiceConfig_IPsec { parent w node service btn } {
|
|
global plugin_img_add plugin_img_del plugin_img_edit
|
|
|
|
set f $w.note.ipsec
|
|
ttk::frame $f
|
|
set h "This IPsec service helper will assist with building an ipsec.sh file"
|
|
set h "$h (located on the Files tab).\nThe IPsec service builds ESP"
|
|
set h "$h tunnels between the specified peers using the racoon IKEv2"
|
|
set h "$h\nkeying daemon. You need to provide keys and the addresses of"
|
|
set h "$h peers, along with the\nsubnets to tunnel."
|
|
ttk::label $f.help -text $h
|
|
pack $f.help -side top -anchor w -padx 4 -pady 4
|
|
$w.note add $f -text "IPsec" -underline 0
|
|
|
|
global g_ipsec_key_dir g_ipsec_key_name
|
|
set g_ipsec_key_dir "/etc/core/keys"
|
|
set g_ipsec_key_name "ipsec1"
|
|
ttk::labelframe $f.keys -text "Keys"
|
|
|
|
ttk::frame $f.keys.dir
|
|
ttk::label $f.keys.dir.lab -text "Key directory:"
|
|
ttk::entry $f.keys.dir.ent -width 40 -textvariable g_ipsec_key_dir
|
|
ttk::button $f.keys.dir.btn -width 5 -text "..." -command {
|
|
set f .popupServicesCustomize.note.ipsec
|
|
set d [$f.keys.dir.ent get]
|
|
set d [tk_chooseDirectory -initialdir $d -title "Key directory"]
|
|
if { $d != "" } {
|
|
$f.keys.dir.ent delete 0 end
|
|
$f.keys.dir.ent insert 0 $d
|
|
}
|
|
}
|
|
pack $f.keys.dir.lab $f.keys.dir.ent $f.keys.dir.btn \
|
|
-side left -padx 4 -pady 4
|
|
pack $f.keys.dir -side top -anchor w
|
|
|
|
ttk::frame $f.keys.name
|
|
ttk::label $f.keys.name.lab -text "Key base name:"
|
|
ttk::entry $f.keys.name.ent -width 10 -textvariable g_ipsec_key_name
|
|
pack $f.keys.name.lab $f.keys.name.ent -side left -padx 4 -pady 4
|
|
pack $f.keys.name -side top -anchor w
|
|
|
|
set h "The (name).pem x509 certificate and (name).key RSA private key need"
|
|
set h "$h to exist in the\nspecified directory. These can be generated"
|
|
set h "$h using the openssl tool. Also, a ca-cert.pem\nfile should exist"
|
|
set h "$h in the key directory for the CA that issued the certs."
|
|
ttk::label $f.keys.help -text $h
|
|
pack $f.keys.help -side top -anchor w -padx 4 -pady 4
|
|
|
|
pack $f.keys -side top -pady 4 -pady 4 -expand true -fill x
|
|
|
|
ttk::labelframe $f.t -text "IPsec Tunnel Endpoints"
|
|
set h "(1) Define tunnel endpoints (select peer node using the button"
|
|
set h "$h, then select address from the list)"
|
|
ttk::label $f.t.lab1 -text $h
|
|
pack $f.t.lab1 -side top -anchor w -padx 4 -pady 4
|
|
ttk::frame $f.t.ep
|
|
ttk::label $f.t.ep.lab1 -text "Local:"
|
|
ttk::combobox $f.t.ep.combo1 -width 12
|
|
pack $f.t.ep.lab1 $f.t.ep.combo1 -side left -padx 4 -pady 4
|
|
populateComboWithIPs $f.t.ep.combo1 $node
|
|
|
|
global g_twoNodeSelect g_twoNodeSelectCallback
|
|
set g_twoNodeSelect ""
|
|
set g_twoNodeSelectCallback selectTwoNodeIPsecCallback
|
|
|
|
set h "Choose a node by clicking it on the canvas"
|
|
set h "$h or\nby selecting it from the list below."
|
|
ttk::label $f.t.ep.lab2 -text "Peer node:"
|
|
ttk::checkbutton $f.t.ep.node -text " (none) " -variable g_twoNodeSelect \
|
|
-onvalue "$f.t.ep.node" -style Toolbutton \
|
|
-command "popupSelectNodes {$h} {} selectNodesIPsecCallback"
|
|
|
|
ttk::label $f.t.ep.lab3 -text "Peer:"
|
|
ttk::combobox $f.t.ep.combo2 -width 12
|
|
ttk::button $f.t.ep.add -text "Add Endpoint" -image $plugin_img_add \
|
|
-compound left -command "ipsecTreeHelper $f ep"
|
|
pack $f.t.ep.lab2 $f.t.ep.node $f.t.ep.lab3 $f.t.ep.combo2 \
|
|
$f.t.ep.add -side left -padx 4 -pady 4
|
|
pack $f.t.ep -side top -anchor w
|
|
|
|
set h "(2) Select endpoints below and add the subnets to be encrypted"
|
|
ttk::label $f.t.lab2 -text $h
|
|
pack $f.t.lab2 -side top -anchor w -padx 4 -pady 4
|
|
|
|
ttk::frame $f.t.sub
|
|
ttk::label $f.t.sub.lab1 -text "Local subnet:"
|
|
ttk::combobox $f.t.sub.combo1 -width 12
|
|
ttk::label $f.t.sub.lab2 -text "Remote subnet:"
|
|
ttk::combobox $f.t.sub.combo2 -width 12
|
|
ttk::button $f.t.sub.add -text "Add Subnet" -image $plugin_img_add \
|
|
-compound left -command "ipsecTreeHelper $f sub"
|
|
pack $f.t.sub.lab1 $f.t.sub.combo1 $f.t.sub.lab2 $f.t.sub.combo2 \
|
|
$f.t.sub.add -side left -padx 5 -pady 4
|
|
pack $f.t.sub -side top -anchor w
|
|
|
|
global node_list
|
|
set net_list [ipv4SubnetList $node_list]
|
|
$f.t.sub.combo1 configure -values $net_list
|
|
$f.t.sub.combo2 configure -values $net_list
|
|
|
|
ttk::treeview $f.t.tree -height 5 -selectmode browse -show tree
|
|
|
|
pack $f.t.tree -side top -padx 4 -pady 4 -fill both
|
|
pack $f.t -side top -expand true -fill both
|
|
|
|
ttk::frame $f.bottom
|
|
ttk::button $f.bottom.del -image $plugin_img_del \
|
|
-command "ipsecTreeHelper $f del"
|
|
ttk::button $f.bottom.gen -text "Generate ipsec.sh" \
|
|
-image $plugin_img_edit -compound left -command "generateIPsecScript $w"
|
|
pack $f.bottom.del $f.bottom.gen -side left -padx 4 -pady 4
|
|
pack $f.bottom -side top
|
|
}
|
|
|
|
#
|
|
# Callback invoked when receiving configuration values
|
|
# from a Configuration Message; this service helper depends on the ipsec.sh
|
|
# file, not the other configuration values.
|
|
#
|
|
#proc popupServiceConfig_IPsec_vals { node values services w } {
|
|
#}
|
|
|
|
#
|
|
# Callback invoked when receiving service file data from a File Message
|
|
proc popupServiceConfig_IPsec_file { node name data w } {
|
|
if { $name == "ipsec.sh" } {
|
|
readIPsecScript $w
|
|
}
|
|
}
|
|
|
|
# helper to insert all of a node's IP addresses into a combo
|
|
proc populateComboWithIPs { combo node } {
|
|
set ip_list [ipv4List $node 0]
|
|
$combo configure -values $ip_list
|
|
$combo delete 0 end
|
|
$combo insert 0 [lindex $ip_list 0]
|
|
}
|
|
|
|
# called from editor.tcl:button1 when user clicks on a node
|
|
# search for IP address and populate
|
|
proc selectTwoNodeIPsecCallback {} {
|
|
set w .popupServicesCustomize
|
|
set f $w.note.ipsec
|
|
|
|
if { ![winfo exists $w] } { return }; # user has closed window
|
|
catch {destroy .nodeselect}
|
|
|
|
set node [string trim [$f.t.ep.node cget -text]]
|
|
if { [set node] == "(none)" } { set node "" }
|
|
|
|
# populate peer interface combo with list of IPs
|
|
populateComboWithIPs $f.t.ep.combo2 $node
|
|
}
|
|
|
|
# called from popupSelectNodes dialog when a node selection has been made
|
|
proc selectNodesIPsecCallback { nodes } {
|
|
global g_twoNodeSelect
|
|
set w .popupServicesCustomize
|
|
set f $w.note.ipsec
|
|
|
|
set g_twoNodeSelect ""
|
|
set node [lindex $nodes 0]
|
|
if { $node == "" } {
|
|
$f.t.ep.node configure -text "(none)"
|
|
return
|
|
}
|
|
$f.t.ep.node configure -text " $node "
|
|
|
|
# populate peer interface combo with list of IPs
|
|
populateComboWithIPs $f.t.ep.combo2 $node
|
|
}
|
|
|
|
# helper to manipulate tree; cmd is "del", "ep" or "sub"
|
|
proc ipsecTreeHelper { f cmd } {
|
|
|
|
if { $cmd == "del" } {
|
|
set sel [$f.t.tree selection]
|
|
$f.t.tree delete $sel
|
|
return
|
|
}
|
|
|
|
# add endpoint (ep) or subnet (sub)
|
|
set l [string trim [$f.t.$cmd.combo1 get]]
|
|
set p [string trim [$f.t.$cmd.combo2 get]]
|
|
if { $l == "" || $p == "" } {
|
|
if { $cmd == "ep" } {
|
|
set h "tunnel interface addresses"
|
|
} else {
|
|
set h "subnet addresses"
|
|
}
|
|
tk_messageBox -type ok -icon warning -message \
|
|
"You need to select local and peer $h."
|
|
return
|
|
}
|
|
|
|
if { $cmd == "ep" } {
|
|
set item [$f.t.tree insert {} end -text "$l <--> $p" -open true]
|
|
$f.t.tree selection set $item
|
|
} elseif { $cmd == "sub" } {
|
|
set parent [$f.t.tree selection]
|
|
if { $parent == "" } {
|
|
tk_messageBox -type ok -icon warning -message \
|
|
"You need to first select endpoints, then configure their subnets."
|
|
return
|
|
}
|
|
if { [$f.t.tree parent $parent] != {} } {
|
|
set parent [$f.t.tree parent $parent]
|
|
}
|
|
$f.t.tree insert $parent end -text "$l <===> $p"
|
|
}
|
|
}
|
|
|
|
# update an ipsec.sh file that was generated by the IPsec service
|
|
proc generateIPsecScript { w } {
|
|
#puts "generateIPsecScript $w..."
|
|
set cfg [$w.note.files.txt get 0.0 end-1c]
|
|
set newcfg ""
|
|
|
|
#
|
|
# Gather data for a new config
|
|
#
|
|
set f $w.note.ipsec
|
|
set keydir [$f.keys.dir.ent get]
|
|
set keyname [$f.keys.name.ent get]
|
|
|
|
set tunnelhosts ""
|
|
set subnet_list ""
|
|
set ti 0
|
|
set th_items [$f.t.tree children {}]
|
|
foreach th $th_items {
|
|
set ep [$f.t.tree item $th -text]
|
|
set i [string first " " $ep]
|
|
# replace " <--> " with "AND"
|
|
set ep [string replace $ep $i $i+5 "AND"]
|
|
# build a list e.g.:
|
|
# tunnelhosts="172.16.0.1AND172.16.0.2 172.16.0.1AND172.16.2.1"
|
|
lappend tunnelhosts $ep
|
|
|
|
set subnets ""
|
|
foreach subnet_item [$f.t.tree children $th] {
|
|
set sn [$f.t.tree item $subnet_item -text]
|
|
set i [string first " " $sn]
|
|
# replace " <===> " with "AND"
|
|
set sn [string replace $sn $i $i+6 "AND"]
|
|
lappend subnets $sn
|
|
}
|
|
incr ti
|
|
set subnetstxt [join $subnets " "]
|
|
# build a list e.g.:
|
|
# T2="172.16.4.0/24AND172.16.5.0/24 172.16.4.0/24AND172.16.6.0/24"
|
|
set subnets "T$ti=\"$subnetstxt\""
|
|
lappend subnet_list $subnets
|
|
}
|
|
|
|
#
|
|
# Perform replacements in existing ipsec.sh file.
|
|
#
|
|
set have_subnets 0
|
|
foreach line [split $cfg "\n"] {
|
|
if { [string range $line 0 6] == "keydir=" } {
|
|
set line "keydir=$keydir"
|
|
} elseif { [string range $line 0 8] == "certname=" } {
|
|
set line "certname=$keyname"
|
|
} elseif { [string range $line 0 11] == "tunnelhosts=" } {
|
|
set tunnelhosts [join $tunnelhosts " "]
|
|
set line "tunnelhosts=\"$tunnelhosts\""
|
|
} elseif { [string range $line 0 0] == "T" && \
|
|
[string is digit [string range $line 1 1]] } {
|
|
if { $have_subnets } {
|
|
continue ;# skip this line
|
|
} else {
|
|
set line [join $subnet_list "\n"]
|
|
set have_subnets 1
|
|
}
|
|
}
|
|
lappend newcfg $line
|
|
}
|
|
$w.note.files.txt delete 0.0 end
|
|
$w.note.files.txt insert 0.0 [join $newcfg "\n"]
|
|
$w.note select $w.note.files
|
|
$w.btn.apply configure -state normal
|
|
}
|
|
|
|
proc readIPsecScript { w } {
|
|
set cfg [$w.note.files.txt get 0.0 end-1c]
|
|
|
|
set f $w.note.ipsec
|
|
$f.keys.dir.ent delete 0 end
|
|
$f.keys.name.ent delete 0 end
|
|
$f.t.tree delete [$f.t.tree children {}]
|
|
|
|
set ti 1
|
|
foreach line [split $cfg "\n"] {
|
|
if { [string range $line 0 6] == "keydir=" } {
|
|
$f.keys.dir.ent insert 0 [string range $line 7 end]
|
|
} elseif { [string range $line 0 8] == "certname=" } {
|
|
$f.keys.name.ent insert 0 [string range $line 9 end]
|
|
} elseif { [string range $line 0 11] == "tunnelhosts=" } {
|
|
set tunnelhosts [string range $line 13 end-1]
|
|
set ti 0
|
|
foreach ep [split $tunnelhosts " "] {
|
|
incr ti
|
|
set i [string first "AND" $ep]
|
|
set ep [string replace $ep $i $i+2 " <--> "]
|
|
$f.t.tree insert {} end -id "T$ti" -text "$ep" -open true
|
|
}
|
|
} elseif { [string range $line 0 0] == "T" && \
|
|
[string is digit [string range $line 1 1]] } {
|
|
set i [string first "=" $line]
|
|
set ti [string range $line 0 $i-1]
|
|
set subnets [split [string range $line $i+2 end-1] " "]
|
|
foreach sn $subnets {
|
|
set i [string first "AND" $sn]
|
|
set sn [string replace $sn $i $i+2 " <===> "]
|
|
if { [catch {$f.t.tree insert $ti end -text "$sn"} e] } {
|
|
puts "IPsec service ignoring line '$ti='"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|