summaryrefslogtreecommitdiffstats
path: root/src/usr/local/www
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/local/www')
-rw-r--r--src/usr/local/www/firewall_aliases_edit.php34
-rw-r--r--src/usr/local/www/firewall_nat_edit.php15
-rw-r--r--src/usr/local/www/firewall_nat_out_edit.php12
-rw-r--r--src/usr/local/www/firewall_rules_edit.php40
-rwxr-xr-xsrc/usr/local/www/interfaces.php5
-rw-r--r--src/usr/local/www/system_certmanager.php156
-rw-r--r--src/usr/local/www/widgets/widgets/gateways.widget.php4
7 files changed, 232 insertions, 34 deletions
diff --git a/src/usr/local/www/firewall_aliases_edit.php b/src/usr/local/www/firewall_aliases_edit.php
index fc4b8b0..4761d9f 100644
--- a/src/usr/local/www/firewall_aliases_edit.php
+++ b/src/usr/local/www/firewall_aliases_edit.php
@@ -611,6 +611,26 @@ $pattern_str = array(
'urltable_ports' => '.*' // Alias Name or URL
);
+$title_str = array(
+ 'network' => 'An IPv4 network address like 1.2.3.0, an IPv6 network address like 1:2a:3b:ffff::0, IP address range, FQDN or an alias',
+ 'host' => 'An IPv4 address like 1.2.3.4, an IPv6 address like 1:2a:3b:ffff::1, IP address range, FQDN or an alias',
+ 'port' => 'A port number, port number range or an alias',
+ 'url' => 'URL',
+ 'url_ports' => 'URL',
+ 'urltable' => 'URL',
+ 'urltable_ports' => 'URL'
+);
+
+$placeholder_str = array(
+ 'network' => 'Address',
+ 'host' => 'Address',
+ 'port' => 'Port',
+ 'url' => 'URL',
+ 'url_ports' => 'URL',
+ 'urltable' => 'URL',
+ 'urltable_ports' => 'URL'
+);
+
$types = array(
'host' => gettext("Host(s)"),
'network' => gettext("Network(s)"),
@@ -715,7 +735,7 @@ while ($counter < count($addresses)) {
$group->add(new Form_IpAddress(
'address' . $counter,
- $tab == 'port' ? 'Port':'Address',
+ 'Address',
$address,
'ALIASV4V6'
))->addMask('address_subnet' . $counter, $address_subnet)->setWidth(4)->setPattern($pattern_str[$tab]);
@@ -787,9 +807,15 @@ events.push(function() {
// Set the input field pattern by tab type
var patternstr = <?=json_encode($pattern_str);?>;
- for (i = 0; i < <?=$counter;?>; i++) {
- $('#address' + i).prop('pattern', patternstr[tab]);
- }
+ var titlestr = <?=json_encode($title_str);?>;
+ var placeholderstr = <?=json_encode($placeholder_str);?>;
+ $("[id^='address']").each(function () {
+ if (/^address[0-9]+$/.test(this.id)) {
+ $('#' + this.id).prop('pattern', patternstr[tab]);
+ $('#' + this.id).prop('title', titlestr[tab]);
+ $('#' + this.id).prop('placeholder', placeholderstr[tab]);
+ }
+ });
// Hide and disable rows other than the first
hideRowsAfter(1, (tab == 'urltable') || (tab == 'urltable_ports'));
diff --git a/src/usr/local/www/firewall_nat_edit.php b/src/usr/local/www/firewall_nat_edit.php
index 96869b5..83440ba 100644
--- a/src/usr/local/www/firewall_nat_edit.php
+++ b/src/usr/local/www/firewall_nat_edit.php
@@ -584,14 +584,16 @@ function build_dsttype_list() {
$list[$ifent . 'ip'] = $ifdesc . ' address';
}
}
-
+
+ //Temporary array so we can sort IPs
+ $templist = array();
if (is_array($config['virtualip']['vip'])) {
foreach ($config['virtualip']['vip'] as $sn) {
if (is_ipaddrv6($sn['subnet'])) {
continue;
}
if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") {
- $list[$sn['subnet'] . '/' . $sn['subnet_bits']] = 'Subnet: ' . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')';
+ $templist[$sn['subnet'] . '/' . $sn['subnet_bits']] = 'Subnet: ' . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')';
if (isset($sn['noexpand'])) {
continue;
}
@@ -602,13 +604,18 @@ function build_dsttype_list() {
for ($i = 0; $i <= $len; $i++) {
$snip = long2ip32($start+$i);
- $list[$snip] = $snip . ' (' . $sn['descr'] . ')';
+ $templist[$snip] = $snip . ' (' . $sn['descr'] . ')';
}
} else {
- $list[$sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')';
+ $templist[$sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')';
}
}
}
+
+ //Sort temp IP array and append onto main array
+ asort($templist);
+ $list = array_merge($list, $templist);
+ unset($templist);
return($list);
}
diff --git a/src/usr/local/www/firewall_nat_out_edit.php b/src/usr/local/www/firewall_nat_out_edit.php
index 92f9060..721eb9e 100644
--- a/src/usr/local/www/firewall_nat_out_edit.php
+++ b/src/usr/local/www/firewall_nat_out_edit.php
@@ -406,10 +406,12 @@ function build_target_list() {
$list[""] = gettext('Interface Address');
+ //Temporary array so we can sort IPs
+ $templist = array();
if (is_array($config['virtualip']['vip'])) {
foreach ($config['virtualip']['vip'] as $sn) {
if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") {
- $list['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')';
+ $templist['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')';
if (isset($sn['noexpand'])) {
continue;
}
@@ -419,13 +421,17 @@ function build_target_list() {
for ($i = 0; $i <= $len; $i++) {
$snip = long2ip32($start+$i);
- $list['I' . $snip] = $snip . ' (' . $sn['descr'] . ')';
+ $templist['I' . $snip] = $snip . ' (' . $sn['descr'] . ')';
}
} else {
- $list['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')';
+ $templist['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')';
}
}
}
+ asort($templist);
+ //Append sorted IP array onto main array
+ $list = array_merge($list, $templist);
+ unset($templist);
foreach ($a_aliases as $alias) {
if ($alias['type'] != "host") {
diff --git a/src/usr/local/www/firewall_rules_edit.php b/src/usr/local/www/firewall_rules_edit.php
index 171cab6..1c11768 100644
--- a/src/usr/local/www/firewall_rules_edit.php
+++ b/src/usr/local/www/firewall_rules_edit.php
@@ -295,6 +295,7 @@ if (isset($id) && $a_filter[$id]) {
if ($_REQUEST['if']) {
$pconfig['interface'] = $_REQUEST['if'];
}
+ $pconfig['ipprotocol'] = "inet"; // other things depend on this, set a sensible default
$pconfig['type'] = "pass";
$pconfig['proto'] = "tcp"; // for new blank rules, default=tcp, also ensures ports fields are visible
$pconfig['src'] = "any";
@@ -319,6 +320,19 @@ if ($_POST['save']) {
if (!array_key_exists($_POST['ipprotocol'], $icmplookup)) {
$input_errors[] = gettext("The IP protocol is not recognized.");
+ unset($_POST['ipprotocol']);
+ }
+
+ // add validation + input error for $_POST['interface']
+
+ $valid = ($_POST['interface'] == "FloatingRules" || isset($_POST['floating'])) ? ['pass','block','reject', 'match'] : ['pass','block','reject'];
+ if (!(is_string($_POST['type']) && in_array($_POST['type'], $valid))) {
+ $input_errors[] = gettext("A valid rule type is not selected.");
+ unset($_POST['type']);
+ }
+
+ if (isset($_POST['tracker']) && !is_numericint($_POST['tracker'])) {
+ unset($_POST['tracker']); // silently unset hidden input if invalid
}
if (isset($a_filter[$id]['associated-rule-id'])) {
@@ -328,7 +342,7 @@ if ($_POST['save']) {
}
}
- if (($_POST['ipprotocol'] <> "") && ($_POST['gateway'] <> "")) {
+ if (isset($_POST['ipprotocol']) && $_POST['gateway'] <> '') {
if (is_array($config['gateways']['gateway_group'])) {
foreach ($config['gateways']['gateway_group'] as $gw_group) {
if ($gw_group['name'] == $_POST['gateway'] && $_POST['ipprotocol'] != $a_gatewaygroups[$_POST['gateway']]['ipprotocol']) {
@@ -423,6 +437,11 @@ if ($_POST['save']) {
$pconfig = $_POST;
+ if (!isset($pconfig['ipprotocol'])) {
+ // other things depend on this, so ensure a valid value if none provided
+ $pconfig['ipprotocol'] = "inet";
+ }
+
if (($_POST['proto'] == "icmp") && count($_POST['icmptype'])) {
$pconfig['icmptype'] = implode(',', $_POST['icmptype']);
} else {
@@ -554,14 +573,14 @@ if ($_POST['save']) {
}
}
if ((is_ipaddrv6($_POST['src']) || is_ipaddrv6($_POST['dst'])) && ($_POST['ipprotocol'] == "inet")) {
- $input_errors[] = gettext("IPv6 addresses cannot be used in IPv4 rules.");
+ $input_errors[] = gettext("IPv6 addresses cannot be used in IPv4 rules (except within an alias).");
}
if ((is_ipaddrv4($_POST['src']) || is_ipaddrv4($_POST['dst'])) && ($_POST['ipprotocol'] == "inet6")) {
- $input_errors[] = gettext("IPv4 addresses can not be used in IPv6 rules.");
+ $input_errors[] = gettext("IPv4 addresses can not be used in IPv6 rules (except within an alias).");
}
if ((is_ipaddr($_POST['src']) || is_ipaddr($_POST['dst'])) && ($_POST['ipprotocol'] == "inet46")) {
- $input_errors[] = gettext("IPv4 and IPv6 addresses can not be used in rules that apply to both IPv4 and IPv6.");
+ $input_errors[] = gettext("IPv4 and IPv6 addresses can not be used in rules that apply to both IPv4 and IPv6 (except within an alias).");
}
if ($_POST['srcbeginport'] > $_POST['srcendport']) {
@@ -593,8 +612,8 @@ if ($_POST['save']) {
} elseif (!isset($t) || count($t) == 0) {
// not specified or none selected
unset($_POST['icmptype']);
- } else {
- // check data
+ } elseif (isset($_POST['ipprotocol'])) {
+ // check data; if ipprotocol invalid then safe to skip this (we can't determine valid icmptypes, but input error already raised for ipprotocol)
$bad_types = array();
if ((count($t) == 1 && !isset($t['any'])) || count($t) > 1) {
// Only need to check valid if just one selected != "any", or >1 selected
@@ -642,7 +661,7 @@ if ($_POST['save']) {
$input_errors[] = gettext("Please select a gateway, normally the interface selected gateway, so the limiters work correctly");
}
}
- if (!empty($_POST['ruleid']) && !ctype_digit($_POST['ruleid'])) {
+ if (!empty($_POST['ruleid']) && !is_numericint($_POST['ruleid'])) {
$input_errors[] = gettext('ID must be an integer');
}
@@ -755,13 +774,12 @@ if ($_POST['save']) {
$filterent['tracker'] = empty($_POST['tracker']) ? (int)microtime(true) : $_POST['tracker'];
$filterent['type'] = $_POST['type'];
+
if (isset($_POST['interface'])) {
$filterent['interface'] = $_POST['interface'];
- }
+ } // FIXME: can $_POST['interface'] be unset at this point, if so then what?
- if (isset($_POST['ipprotocol'])) {
- $filterent['ipprotocol'] = $_POST['ipprotocol'];
- }
+ $filterent['ipprotocol'] = $_POST['ipprotocol'];
if ($_POST['tcpflags_any']) {
$filterent['tcpflags_any'] = true;
diff --git a/src/usr/local/www/interfaces.php b/src/usr/local/www/interfaces.php
index e00856d..fd9965b 100755
--- a/src/usr/local/www/interfaces.php
+++ b/src/usr/local/www/interfaces.php
@@ -987,10 +987,7 @@ if ($_POST['apply']) {
kill_dhclient_process($wancfg['if']);
}
if ($wancfg['ipaddrv6'] == "dhcp6") {
- $pid = find_dhcp6c_process($wancfg['if']);
- if ($pid) {
- posix_kill($pid, SIGTERM);
- }
+ kill_dhcp6client_process($wancfg['if'],true);
}
}
$ppp = array();
diff --git a/src/usr/local/www/system_certmanager.php b/src/usr/local/www/system_certmanager.php
index 777d416..7b5ea66 100644
--- a/src/usr/local/www/system_certmanager.php
+++ b/src/usr/local/www/system_certmanager.php
@@ -34,6 +34,7 @@ $cert_methods = array(
"import" => gettext("Import an existing Certificate"),
"internal" => gettext("Create an internal Certificate"),
"external" => gettext("Create a Certificate Signing Request"),
+ "sign" => gettext("Sign a Certificate Signing Request")
);
$cert_keylens = array("512", "1024", "2048", "3072", "4096", "7680", "8192", "15360", "16384");
@@ -81,7 +82,6 @@ foreach ($a_ca as $ca) {
$act = $_REQUEST['act'];
-
if ($_POST['act'] == "del") {
if (!isset($a_cert[$id])) {
@@ -96,7 +96,6 @@ if ($_POST['act'] == "del") {
exit;
}
-
if ($act == "new") {
$pconfig['method'] = $_POST['method'];
$pconfig['keylen'] = "2048";
@@ -172,6 +171,7 @@ if ($act == "p12") {
$args['friendly_name'] = $a_cert[$id]['descr'];
$ca = lookup_ca($a_cert[$id]['caref']);
+
if ($ca) {
$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
}
@@ -212,6 +212,24 @@ if ($_POST['save']) {
$pconfig = $_POST;
/* input validation */
+ if ($pconfig['method'] == "sign") {
+ $reqdfields = explode(" ",
+ "descr catosignwith");
+ $reqdfieldsn = array(
+ gettext("Descriptive name"),
+ gettext("CA to sign with"));
+
+ if (($_POST['csrtosign'] === "new") && (!strstr($_POST['csrpaste'], "BEGIN CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END CERTIFICATE REQUEST"))) {
+ $input_errors[] = gettext("This signing request does not appear to be valid.");
+ }
+
+ if ( (($_POST['csrtosign'] === "new") && (strlen($_POST['keypaste']) > 0)) && (!strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") || !strstr($_POST['keypaste'], "END PRIVATE KEY"))) {
+ $input_errors[] = gettext("This private does not appear to be valid.");
+ $input_errors[] = gettext("Key data field should be blank, or a valid x509 private key");
+ }
+
+ }
+
if ($pconfig['method'] == "import") {
$reqdfields = explode(" ",
"descr cert key");
@@ -222,6 +240,7 @@ if ($_POST['save']) {
if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
$input_errors[] = gettext("This certificate does not appear to be valid.");
}
+
if (cert_get_modulus($_POST['cert'], false) != prv_get_modulus($_POST['key'], false)) {
$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
}
@@ -267,6 +286,7 @@ if ($_POST['save']) {
$altnames = array();
do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
+
if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
/* subjectAltNames */
foreach ($_POST as $key => $value) {
@@ -362,6 +382,48 @@ if ($_POST['save']) {
if ($cert && $a_user) {
$a_user[$userid]['cert'][] = $cert['refid'];
}
+ } else if ($pconfig['method'] == "sign") { // Sign a CSR
+ $csrid = lookup_cert($pconfig['csrtosign']);
+ $caid = lookup_ca($pconfig['catosignwith']);
+
+ // Read the CSR from $config, or if a new one, from the textarea
+ if ($pconfig['csrtosign'] === "new") {
+ $csr = $pconfig['csrpaste'];
+ } else {
+ $csr = base64_decode($csrid['csr']);
+ }
+
+ $old_err_level = error_reporting(0);
+
+ // Gather the information required for signed cert
+ $ca = base64_decode($caid['crt']);
+ $key = base64_decode($caid['prv']);
+ $duration = $pconfig['duration'];
+ $caref = $pconfig['catosignwith'];
+ $type = (cert_get_purpose($csrid)['server'] === "Yes") ? "server":"user";
+
+ // Sign the new cert and export it in x509 format
+ openssl_x509_export(openssl_csr_sign($csr, $ca, $key, $duration, ['x509_extensions' => 'v3_req']), $n509);
+
+ // Gather the details required to save the new cert
+ $newcert = array();
+ $newcert['refid'] = uniqid();
+ $newcert['caref'] = $caref;
+ $newcert['descr'] = $pconfig['descr'];
+ $newcert['type'] = $type;
+ $newcert['crt'] = base64_encode($n509);
+
+ if ($pconfig['csrtosign'] === "new") {
+ $newcert['prv'] = base64_encode($pconfig['keypaste']);
+ } else {
+ $newcert['prv'] = $csrid['prv'];
+ }
+
+ // Add it to the config file
+ $config['cert'][] = $newcert;
+
+ error_reporting($old_err_level);
+
} else {
$cert = array();
$cert['refid'] = uniqid();
@@ -435,6 +497,7 @@ if ($_POST['save']) {
}
}
}
+
error_reporting($old_err_level);
if (isset($id) && $a_cert[$id]) {
@@ -569,7 +632,7 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
));
}
- $section = new Form_Section('Add a New Certificate');
+ $section = new Form_Section('Add/Sign a New Certificate');
if (!isset($id)) {
$section->addInput(new Form_Select(
@@ -588,6 +651,73 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
))->addClass('toggle-existing');
$form->add($section);
+
+ // Return an array containing the IDs od all CAs
+ function list_cas() {
+ global $a_ca;
+ $allCas = array();
+
+ foreach ($a_ca as $ca) {
+ if ($ca['prv']) {
+ $allCas[$ca['refid']] = $ca['descr'];
+ }
+ }
+
+ return $allCas;
+ }
+
+ // Return an array containing the IDs od all CSRs
+ function list_csrs() {
+ global $config;
+ $allCsrs = array();
+
+ foreach ($config['cert'] as $cert) {
+ if ($cert['csr']) {
+ $allCsrs[$cert['refid']] = $cert['descr'];
+ }
+ }
+
+ return ['new' => gettext('New CSR (Paste below)')] + $allCsrs;
+ }
+
+ $section = new Form_Section('Sign CSR');
+ $section->addClass('toggle-sign collapse');
+
+ $section->AddInput(new Form_Select(
+ 'catosignwith',
+ '*CA to sign with',
+ $pconfig['catosignwith'],
+ list_cas()
+ ));
+
+ $section->AddInput(new Form_Select(
+ 'csrtosign',
+ '*CSR to sign',
+ isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new',
+ list_csrs()
+ ));
+
+ $section->addInput(new Form_Input(
+ 'duration',
+ '*Certificate duration (days)',
+ 'number',
+ $pconfig['duration'] ? $pconfig['duration']:'3650'
+ ));
+
+ $section->addInput(new Form_Textarea(
+ 'csrpaste',
+ 'CSR data',
+ $pconfig['csrpaste']
+ ))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.');
+
+ $section->addInput(new Form_Textarea(
+ 'keypaste',
+ 'Key data',
+ $pconfig['keypaste']
+ ))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in pfSense');
+
+ $form->add($section);
+
$section = new Form_Section('Import Certificate');
$section->addClass('toggle-import collapse');
@@ -1062,7 +1192,9 @@ foreach ($a_cert as $i => $cert):
<td>
<?php if (!$cert['csr']): ?>
<a href="system_certmanager.php?act=exp&amp;id=<?=$i?>" class="fa fa-certificate" title="<?=gettext("Export Certificate")?>"></a>
- <a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
+ <?php if ($cert['prv']): ?>
+ <a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
+ <?php endif?>
<a href="system_certmanager.php?act=p12&amp;id=<?=$i?>" class="fa fa-archive" title="<?=gettext("Export P12")?>"></a>
<?php else: ?>
<a href="system_certmanager.php?act=csr&amp;id=<?=$i?>" class="fa fa-pencil" title="<?=gettext("Update CSR")?>"></a>
@@ -1086,7 +1218,7 @@ foreach ($a_cert as $i => $cert):
<nav class="action-buttons">
<a href="?act=new" class="btn btn-success btn-sm">
<i class="fa fa-plus icon-embed-btn"></i>
- <?=gettext("Add")?>
+ <?=gettext("Add/Sign")?>
</a>
</nav>
<?php
@@ -1113,7 +1245,6 @@ events.push(function() {
}
$subject = cert_get_subject_array($ca['crt']);
-
?>
case "<?=$ca['refid'];?>":
$('#dn_country').val("<?=$subject[0]['v'];?>");
@@ -1129,15 +1260,28 @@ events.push(function() {
}
}
+ function set_csr_ro() {
+ var newcsr = ($('#csrtosign').val() == "new");
+
+ $('#csrpaste').attr('readonly', !newcsr);
+ $('#keypaste').attr('readonly', !newcsr);
+ setRequired('csrpaste', newcsr);
+ }
+
// ---------- Click checkbox handlers ---------------------------------------------------------
$('#caref').on('change', function() {
internalca_change();
});
+ $('#csrtosign').change(function () {
+ set_csr_ro();
+ });
+
// ---------- On initial page load ------------------------------------------------------------
internalca_change();
+ set_csr_ro();
// Suppress "Delete row" button if there are fewer than two rows
checkLastRow();
diff --git a/src/usr/local/www/widgets/widgets/gateways.widget.php b/src/usr/local/www/widgets/widgets/gateways.widget.php
index d414a5e..355dd4a 100644
--- a/src/usr/local/www/widgets/widgets/gateways.widget.php
+++ b/src/usr/local/www/widgets/widgets/gateways.widget.php
@@ -310,8 +310,8 @@ function compose_table_body_contents() {
$bgcolor = "info"; // lightblue
}
- $rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['delay']) : gettext("Pending")) . "</td>\n";
- $rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['stddev']) : gettext("Pending")) . "</td>\n";
+ $rtnstr .= "<td>" . ($gateways_status[$gname] ? ($gateways_status[$gname]['delay'] ? htmlspecialchars(number_format((float)rtrim($gateways_status[$gname]['delay'], "ms"), 1)) . "ms" : '') : gettext("Pending")) . "</td>\n";
+ $rtnstr .= "<td>" . ($gateways_status[$gname] ? ($gateways_status[$gname]['stddev'] ? htmlspecialchars(number_format((float)rtrim($gateways_status[$gname]['stddev'], "ms"), 1)) . "ms" : '') : gettext("Pending")) . "</td>\n";
$rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['loss']) : gettext("Pending")) . "</td>\n";
$rtnstr .= '<td class="bg-' . $bgcolor . '">' . $online . "</td>\n";
$rtnstr .= "</tr>\n";
OpenPOWER on IntegriCloud