summaryrefslogtreecommitdiffstats
path: root/src/etc
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-08-25 08:08:24 -0300
committerRenato Botelho <renato@netgate.com>2015-08-25 14:49:54 -0300
commit46bc6e545a17e77202aaf01ec0cd8d5a46567525 (patch)
tree32d18dda436ec739c67c489ceb771e8629cd926f /src/etc
parent4d9801c2dbd2b3e54a39578ee62b93af66607227 (diff)
downloadpfsense-46bc6e545a17e77202aaf01ec0cd8d5a46567525.zip
pfsense-46bc6e545a17e77202aaf01ec0cd8d5a46567525.tar.gz
Move main pfSense content to src/
Diffstat (limited to 'src/etc')
-rw-r--r--src/etc/ascii-art/pfsense-logo-small.txt5
-rw-r--r--src/etc/bogons10
-rw-r--r--src/etc/bogonsv60
-rw-r--r--src/etc/ca_countries237
-rw-r--r--src/etc/crontab5
-rw-r--r--src/etc/ddb.conf3
-rw-r--r--src/etc/devd.conf80
-rw-r--r--src/etc/dh-parameters.10245
-rw-r--r--src/etc/dh-parameters.20488
-rw-r--r--src/etc/dh-parameters.409613
-rw-r--r--src/etc/disktab204
-rwxr-xr-xsrc/etc/ecl.php189
-rw-r--r--src/etc/fbtab4
-rw-r--r--src/etc/gettytab235
-rw-r--r--src/etc/group31
-rw-r--r--src/etc/host.conf7
-rw-r--r--src/etc/hosts.allow5
-rw-r--r--src/etc/inc/CHAP.inc463
-rw-r--r--src/etc/inc/IPv6.inc1110
-rw-r--r--src/etc/inc/PEAR.inc1103
-rw-r--r--src/etc/inc/auth.inc1627
-rw-r--r--src/etc/inc/authgui.inc335
-rw-r--r--src/etc/inc/basic_sasl_client.inc63
-rw-r--r--src/etc/inc/captiveportal.inc2409
-rw-r--r--src/etc/inc/certs.inc867
-rw-r--r--src/etc/inc/config.console.inc560
-rw-r--r--src/etc/inc/config.gui.inc96
-rw-r--r--src/etc/inc/config.inc226
-rw-r--r--src/etc/inc/config.lib.inc1020
-rw-r--r--src/etc/inc/cram_md5_sasl_client.inc67
-rw-r--r--src/etc/inc/crypt.inc101
-rw-r--r--src/etc/inc/digest_sasl_client.inc135
-rw-r--r--src/etc/inc/dot.hushlogin0
-rw-r--r--src/etc/inc/dyndns.class1634
-rw-r--r--src/etc/inc/easyrule.inc495
-rw-r--r--src/etc/inc/filter.inc4228
-rw-r--r--src/etc/inc/filter_log.inc441
-rw-r--r--src/etc/inc/functions.inc158
-rw-r--r--src/etc/inc/globals.inc195
-rw-r--r--src/etc/inc/gmirror.inc342
-rw-r--r--src/etc/inc/growl.class102
-rw-r--r--src/etc/inc/gwlb.inc1252
-rw-r--r--src/etc/inc/interfaces.inc5814
-rw-r--r--src/etc/inc/ipsec.attributes.php200
-rwxr-xr-xsrc/etc/inc/ipsec.auth-user.php169
-rw-r--r--src/etc/inc/ipsec.inc777
-rw-r--r--src/etc/inc/itemid.inc108
-rw-r--r--src/etc/inc/led.inc356
-rw-r--r--src/etc/inc/login_sasl_client.inc69
-rw-r--r--src/etc/inc/meta.inc215
-rw-r--r--src/etc/inc/notices.inc453
-rw-r--r--src/etc/inc/ntlm_sasl_client.inc180
-rw-r--r--src/etc/inc/openvpn.attributes.php203
-rw-r--r--src/etc/inc/openvpn.auth-user.php213
-rw-r--r--src/etc/inc/openvpn.inc1589
-rw-r--r--src/etc/inc/openvpn.tls-verify.php97
-rw-r--r--src/etc/inc/pfsense-utils.inc3211
-rw-r--r--src/etc/inc/pkg-utils.inc953
-rw-r--r--src/etc/inc/plain_sasl_client.inc99
-rw-r--r--src/etc/inc/priv.defs.inc1403
-rw-r--r--src/etc/inc/priv.inc337
-rw-r--r--src/etc/inc/priv/user.priv.inc74
-rw-r--r--src/etc/inc/r53.class754
-rw-r--r--src/etc/inc/radius.inc1208
-rw-r--r--src/etc/inc/rrd.inc989
-rw-r--r--src/etc/inc/sasl.inc422
-rw-r--r--src/etc/inc/service-utils.inc749
-rw-r--r--src/etc/inc/services.inc2541
-rw-r--r--src/etc/inc/shaper.inc4969
-rw-r--r--src/etc/inc/simplepie/LICENSE.txt26
-rw-r--r--src/etc/inc/simplepie/simplepie.inc13672
-rw-r--r--src/etc/inc/smtp.inc862
-rw-r--r--src/etc/inc/system.inc2258
-rw-r--r--src/etc/inc/unbound.inc717
-rw-r--r--src/etc/inc/upgrade_config.inc3825
-rw-r--r--src/etc/inc/util.inc2259
-rw-r--r--src/etc/inc/uuid.php327
-rw-r--r--src/etc/inc/voucher.inc785
-rw-r--r--src/etc/inc/vpn.inc2056
-rw-r--r--src/etc/inc/vslb.inc564
-rw-r--r--src/etc/inc/wizardapp.inc668
-rw-r--r--src/etc/inc/xmlparse.inc334
-rw-r--r--src/etc/inc/xmlparse_attr.inc237
-rw-r--r--src/etc/inc/xmlreader.inc277
-rw-r--r--src/etc/inc/xmlrpc.inc148
-rw-r--r--src/etc/inc/xmlrpc_client.inc2060
-rw-r--r--src/etc/inc/xmlrpc_server.inc678
-rw-r--r--src/etc/inc/zeromq.inc340
-rw-r--r--src/etc/inetd.conf1
-rw-r--r--src/etc/login.conf317
-rw-r--r--src/etc/master.passwd29
-rw-r--r--src/etc/motd0
-rw-r--r--src/etc/mtree/BSD.local.dist0
-rw-r--r--src/etc/networks17
-rw-r--r--src/etc/passwd26
-rw-r--r--src/etc/pf.os698
-rw-r--r--src/etc/pfSense.obsoletedfiles1018
-rw-r--r--src/etc/phpshellsessions/changepassword79
-rw-r--r--src/etc/phpshellsessions/disablecarp17
-rw-r--r--src/etc/phpshellsessions/disabledhcpd13
-rw-r--r--src/etc/phpshellsessions/disablereferercheck11
-rw-r--r--src/etc/phpshellsessions/enableallowallwan36
-rw-r--r--src/etc/phpshellsessions/enablecarp23
-rw-r--r--src/etc/phpshellsessions/enablesshd12
-rw-r--r--src/etc/phpshellsessions/externalconfiglocator3
-rw-r--r--src/etc/phpshellsessions/generateguicert8
-rw-r--r--src/etc/phpshellsessions/gitsync434
-rw-r--r--src/etc/phpshellsessions/installpkg36
-rw-r--r--src/etc/phpshellsessions/listpkg16
-rw-r--r--src/etc/phpshellsessions/removepkgconfig8
-rw-r--r--src/etc/phpshellsessions/removeshaper25
-rw-r--r--src/etc/phpshellsessions/restartdhcpd4
-rw-r--r--src/etc/phpshellsessions/restartipsec7
-rw-r--r--src/etc/phpshellsessions/svc99
-rw-r--r--src/etc/phpshellsessions/uninstallpkg34
-rw-r--r--src/etc/platform1
-rw-r--r--src/etc/printcap0
-rw-r--r--src/etc/protocols158
-rw-r--r--src/etc/pubkey.pem1
-rwxr-xr-xsrc/etc/rc439
-rwxr-xr-xsrc/etc/rc.backup_dhcpleases.sh8
-rwxr-xr-xsrc/etc/rc.backup_rrd.sh27
-rwxr-xr-xsrc/etc/rc.banner123
-rwxr-xr-xsrc/etc/rc.bootup428
-rwxr-xr-xsrc/etc/rc.captiveportal_configure40
-rwxr-xr-xsrc/etc/rc.captiveportal_configure_mac52
-rwxr-xr-xsrc/etc/rc.carpbackup97
-rwxr-xr-xsrc/etc/rc.carpmaster105
-rwxr-xr-xsrc/etc/rc.cdrom39
-rw-r--r--src/etc/rc.conf1
-rwxr-xr-xsrc/etc/rc.conf_mount_ro36
-rwxr-xr-xsrc/etc/rc.conf_mount_rw36
-rwxr-xr-xsrc/etc/rc.create_full_backup18
-rwxr-xr-xsrc/etc/rc.d/etcmfs80
-rwxr-xr-xsrc/etc/rc.d/hostid137
-rwxr-xr-xsrc/etc/rc.d/varmfs66
-rwxr-xr-xsrc/etc/rc.dhclient_cron53
-rwxr-xr-xsrc/etc/rc.disable_hdd_apm13
-rwxr-xr-xsrc/etc/rc.dumpon30
-rwxr-xr-xsrc/etc/rc.dyndns.update58
-rwxr-xr-xsrc/etc/rc.embedded32
-rwxr-xr-xsrc/etc/rc.expireaccounts70
-rwxr-xr-xsrc/etc/rc.filter_configure43
-rwxr-xr-xsrc/etc/rc.filter_configure_sync41
-rwxr-xr-xsrc/etc/rc.filter_configure_xmlrpc53
-rwxr-xr-xsrc/etc/rc.filter_synchronize488
-rwxr-xr-xsrc/etc/rc.firmware476
-rwxr-xr-xsrc/etc/rc.firmware_auto72
-rwxr-xr-xsrc/etc/rc.halt13
-rwxr-xr-xsrc/etc/rc.initial167
-rwxr-xr-xsrc/etc/rc.initial.defaults62
-rwxr-xr-xsrc/etc/rc.initial.firmware_update190
-rwxr-xr-xsrc/etc/rc.initial.halt61
-rwxr-xr-xsrc/etc/rc.initial.password89
-rwxr-xr-xsrc/etc/rc.initial.ping55
-rwxr-xr-xsrc/etc/rc.initial.reboot61
-rwxr-xr-xsrc/etc/rc.initial.setlanip556
-rwxr-xr-xsrc/etc/rc.initial.setports51
-rwxr-xr-xsrc/etc/rc.initial.store_config_to_removable_device93
-rwxr-xr-xsrc/etc/rc.initial.toggle_sshd75
-rwxr-xr-xsrc/etc/rc.interfaces_carp_configure39
-rwxr-xr-xsrc/etc/rc.interfaces_lan_configure39
-rwxr-xr-xsrc/etc/rc.interfaces_opt_configure41
-rwxr-xr-xsrc/etc/rc.interfaces_wan_configure50
-rwxr-xr-xsrc/etc/rc.kill_states94
-rwxr-xr-xsrc/etc/rc.linkup165
-rwxr-xr-xsrc/etc/rc.nanobsd_switch_boot_slice27
-rwxr-xr-xsrc/etc/rc.newipsecdns61
-rwxr-xr-xsrc/etc/rc.newroutedns59
-rwxr-xr-xsrc/etc/rc.newwanip268
-rwxr-xr-xsrc/etc/rc.newwanipv6204
-rwxr-xr-xsrc/etc/rc.notify_message64
-rwxr-xr-xsrc/etc/rc.ntpdate39
-rwxr-xr-xsrc/etc/rc.openvpn132
-rwxr-xr-xsrc/etc/rc.packages88
-rwxr-xr-xsrc/etc/rc.php-fpm_restart17
-rwxr-xr-xsrc/etc/rc.php_ini_setup417
-rwxr-xr-xsrc/etc/rc.prunecaptiveportal66
-rwxr-xr-xsrc/etc/rc.reboot35
-rwxr-xr-xsrc/etc/rc.reload_all46
-rwxr-xr-xsrc/etc/rc.reload_interfaces45
-rwxr-xr-xsrc/etc/rc.resolv_conf_generate36
-rwxr-xr-xsrc/etc/rc.restart_webgui28
-rwxr-xr-xsrc/etc/rc.restore_config_backup129
-rwxr-xr-xsrc/etc/rc.restore_full_backup20
-rwxr-xr-xsrc/etc/rc.savecore22
-rwxr-xr-xsrc/etc/rc.savevoucher40
-rwxr-xr-xsrc/etc/rc.shutdown37
-rwxr-xr-xsrc/etc/rc.start_packages88
-rwxr-xr-xsrc/etc/rc.stop_packages5
-rwxr-xr-xsrc/etc/rc.update_alias_url_data43
-rwxr-xr-xsrc/etc/rc.update_bogons.sh152
-rwxr-xr-xsrc/etc/rc.update_urltables60
-rw-r--r--src/etc/services4111
-rw-r--r--src/etc/shells12
-rw-r--r--src/etc/skel/dot.profile5
-rw-r--r--src/etc/skel/dot.shrc14
-rw-r--r--src/etc/skel/dot.tcshrc30
-rw-r--r--src/etc/ssh/sshd_config103
-rwxr-xr-xsrc/etc/sshd207
-rw-r--r--src/etc/ssl/openssl.cnf309
-rw-r--r--src/etc/syslog.conf12
-rw-r--r--src/etc/ttys49
-rw-r--r--src/etc/version1
204 files changed, 95589 insertions, 0 deletions
diff --git a/src/etc/ascii-art/pfsense-logo-small.txt b/src/etc/ascii-art/pfsense-logo-small.txt
new file mode 100644
index 0000000..01d8bc5
--- /dev/null
+++ b/src/etc/ascii-art/pfsense-logo-small.txt
@@ -0,0 +1,5 @@
+ ___
+ ___/ f \
+/ p \___/ Sense
+\___/ \
+ \___/ \ No newline at end of file
diff --git a/src/etc/bogons b/src/etc/bogons
new file mode 100644
index 0000000..9be218d
--- /dev/null
+++ b/src/etc/bogons
@@ -0,0 +1,10 @@
+0.0.0.0/8
+127.0.0.0/8
+169.254.0.0/16
+192.0.0.0/24
+192.0.2.0/24
+198.18.0.0/15
+198.51.100.0/24
+203.0.113.0/24
+224.0.0.0/4
+240.0.0.0/4
diff --git a/src/etc/bogonsv6 b/src/etc/bogonsv6
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/etc/bogonsv6
diff --git a/src/etc/ca_countries b/src/etc/ca_countries
new file mode 100644
index 0000000..1a9ca9e
--- /dev/null
+++ b/src/etc/ca_countries
@@ -0,0 +1,237 @@
+US United States of America
+CA Canada
+AX Aland Islands
+AD Andorra
+AE United Arab Emirates
+AF Afghanistan
+AG Antigua and Barbuda
+AI Anguilla
+AL Albania
+AM Armenia
+AN Netherlands Antilles
+AO Angola
+AQ Antarctica
+AR Argentina
+AS American Samoa
+AT Austria
+AU Australia
+AW Aruba
+AZ Azerbaijan
+BA Bosnia and Herzegovina
+BB Barbados
+BD Bangladesh
+BE Belgium
+BF Burkina Faso
+BG Bulgaria
+BH Bahrain
+BI Burundi
+BJ Benin
+BM Bermuda
+BN Brunei Darussalam
+BO Bolivia
+BR Brazil
+BS Bahamas
+BT Bhutan
+BV Bouvet Island
+BW Botswana
+BZ Belize
+CA Canada
+CC Cocos (Keeling) Islands
+CF Central African Republic
+CH Switzerland
+CI Cote D'Ivoire (Ivory Coast)
+CK Cook Islands
+CL Chile
+CM Cameroon
+CN China
+CO Colombia
+CR Costa Rica
+CS Czechoslovakia (former)
+CV Cape Verde
+CX Christmas Island
+CY Cyprus
+CZ Czech Republic
+DE Germany
+DJ Djibouti
+DK Denmark
+DM Dominica
+DO Dominican Republic
+DZ Algeria
+EC Ecuador
+EE Estonia
+EG Egypt
+EH Western Sahara
+ER Eritrea
+ES Spain
+ET Ethiopia
+FI Finland
+FJ Fiji
+FK Falkland Islands (Malvinas)
+FM Micronesia
+FO Faroe Islands
+FR France
+FX France, Metropolitan
+GA Gabon
+GB Great Britain (UK)
+GD Grenada
+GE Georgia
+GF French Guiana
+GG Guernsey
+GH Ghana
+GI Gibraltar
+GL Greenland
+GM Gambia
+GN Guinea
+GP Guadeloupe
+GQ Equatorial Guinea
+GR Greece
+GS S. Georgia and S. Sandwich Isls.
+GT Guatemala
+GU Guam
+GW Guinea-Bissau
+GY Guyana
+HK Hong Kong
+HM Heard and McDonald Islands
+HN Honduras
+HR Croatia (Hrvatska)
+HT Haiti
+HU Hungary
+ID Indonesia
+IE Ireland
+IL Israel
+IM Isle of Man
+IN India
+IO British Indian Ocean Territory
+IS Iceland
+IT Italy
+JE Jersey
+JM Jamaica
+JO Jordan
+JP Japan
+KE Kenya
+KG Kyrgyzstan
+KH Cambodia
+KI Kiribati
+KM Comoros
+KN Saint Kitts and Nevis
+KR Korea (South)
+KW Kuwait
+KY Cayman Islands
+KZ Kazakhstan
+LA Laos
+LC Saint Lucia
+LI Liechtenstein
+LK Sri Lanka
+LS Lesotho
+LT Lithuania
+LU Luxembourg
+LV Latvia
+LY Libya
+MA Morocco
+MC Monaco
+MD Moldova
+ME Montenegro
+MG Madagascar
+MH Marshall Islands
+MK Macedonia
+ML Mali
+MM Myanmar
+MN Mongolia
+MO Macau
+MP Northern Mariana Islands
+MQ Martinique
+MR Mauritania
+MS Montserrat
+MT Malta
+MU Mauritius
+MV Maldives
+MW Malawi
+MX Mexico
+MY Malaysia
+MZ Mozambique
+NA Namibia
+NC New Caledonia
+NE Niger
+NF Norfolk Island
+NG Nigeria
+NI Nicaragua
+NL Netherlands
+NO Norway
+NP Nepal
+NR Nauru
+NT Neutral Zone
+NU Niue
+NZ New Zealand (Aotearoa)
+OM Oman
+PA Panama
+PE Peru
+PF French Polynesia
+PG Papua New Guinea
+PH Philippines
+PK Pakistan
+PL Poland
+PM St. Pierre and Miquelon
+PN Pitcairn
+PR Puerto Rico
+PS Palestinian Territory
+PT Portugal
+PW Palau
+PY Paraguay
+QA Qatar
+RE Reunion
+RO Romania
+RS Serbia
+RU Russian Federation
+RW Rwanda
+SA Saudi Arabia
+SB Solomon Islands
+SC Seychelles
+SE Sweden
+SG Singapore
+SH St. Helena
+SI Slovenia
+SJ Svalbard and Jan Mayen Islands
+SK Slovak Republic
+SL Sierra Leone
+SM San Marino
+SN Senegal
+SR Suriname
+ST Sao Tome and Principe
+SU USSR (former)
+SV El Salvador
+SZ Swaziland
+TC Turks and Caicos Islands
+TD Chad
+TF French Southern Territories
+TG Togo
+TH Thailand
+TJ Tajikistan
+TK Tokelau
+TM Turkmenistan
+TN Tunisia
+TO Tonga
+TP East Timor
+TR Turkey
+TT Trinidad and Tobago
+TV Tuvalu
+TW Taiwan
+TZ Tanzania
+UA Ukraine
+UG Uganda
+UM US Minor Outlying Islands
+US United States
+UY Uruguay
+UZ Uzbekistan
+VA Vatican City State (Holy See)
+VC Saint Vincent and the Grenadines
+VE Venezuela
+VG Virgin Islands (British)
+VI Virgin Islands (U.S.)
+VN Viet Nam
+VU Vanuatu
+WF Wallis and Futuna Islands
+WS Samoa
+YE Yemen
+YT Mayotte
+ZA South Africa
+ZM Zambia \ No newline at end of file
diff --git a/src/etc/crontab b/src/etc/crontab
new file mode 100644
index 0000000..8be8494
--- /dev/null
+++ b/src/etc/crontab
@@ -0,0 +1,5 @@
+SHELL=/bin/sh
+PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
+HOME=/var/log
+#minute hour mday month wday who command
+# \ No newline at end of file
diff --git a/src/etc/ddb.conf b/src/etc/ddb.conf
new file mode 100644
index 0000000..65f49c2
--- /dev/null
+++ b/src/etc/ddb.conf
@@ -0,0 +1,3 @@
+script lockinfo=show locks; show alllocks; show lockedvnods
+script kdb.enter.default=textdump set; capture on; run lockinfo; show pcpu; bt; ps; alltrace; capture off; call doadump; reset
+script kdb.enter.witness=run lockinfo
diff --git a/src/etc/devd.conf b/src/etc/devd.conf
new file mode 100644
index 0000000..ea67ba6
--- /dev/null
+++ b/src/etc/devd.conf
@@ -0,0 +1,80 @@
+# $Id$
+# $FreeBSD: src/etc/devd.conf,v 1.26.2.1 2005/09/03 22:49:22 sam Exp $
+
+options {
+ directory "/etc/devd";
+ directory "/usr/local/etc/devd";
+ pid-file "/var/run/devd.pid";
+ set scsi-controller-regex
+ "(aac|adv|adw|aha|ahb|ahc|ahd|aic|amd|amr|asr|bt|ciss|ct|dpt|\
+ esp|ida|iir|ips|isp|mlx|mly|mpt|ncr|ncv|nsp|stg|sym|trm|wds)\
+ [0-9]+";
+};
+
+# CARP notify hooks. This will call carpup/carpdown with the
+# interface (carp0, carp1) as the first parameter.
+notify 100 {
+ match "system" "CARP";
+ match "type" "MASTER";
+ action "/usr/local/sbin/pfSctl -c 'interface carpmaster $subsystem'";
+};
+
+notify 100 {
+ match "system" "CARP";
+ match "type" "BACKUP";
+ action "/usr/local/sbin/pfSctl -c 'interface carpbackup $subsystem'";
+};
+
+notify 100 {
+ match "system" "CARP";
+ match "type" "INIT";
+ action "/usr/local/sbin/pfSctl -c 'interface carpbackup $subsystem'";
+};
+
+# When a USB keyboard arrives, attach it as the console keyboard.
+attach 100 {
+ device-name "ukbd0";
+ action "kbdcontrol -k /dev/ukbd0 < /dev/console 2>/dev/null";
+};
+
+detach 100 {
+ device-name "ukbd0";
+ action "kbdcontrol -k /dev/kbd0 < /dev/console 2>/dev/null";
+};
+
+#
+# Signal upper levels that an event happened on ethernet class interface
+#
+notify 0 {
+ match "system" "IFNET";
+ match "type" "LINK_UP";
+ media-type "ethernet";
+ action "/usr/local/sbin/pfSctl -c 'interface linkup start $subsystem'";
+};
+
+notify 0 {
+ match "system" "IFNET";
+ match "type" "LINK_DOWN";
+ media-type "ethernet";
+ action "/usr/local/sbin/pfSctl -c 'interface linkup stop $subsystem'";
+};
+
+#
+# Signal upper levels that an event happened on 802.11 class interface
+#
+notify 0 {
+ match "system" "IFNET";
+ match "type" "LINK_UP";
+ match "subsystem" "[a-z]+[0-9]+_wlan[0-9]+";
+ action "/usr/local/sbin/pfSctl -c 'interface linkup start $subsystem'";
+};
+
+# Notify all users before beginning emergency shutdown when we get
+# a _CRT or _HOT thermal event and we're going to power down the system
+# very soon.
+notify 10 {
+ match "system" "ACPI";
+ match "subsystem" "Thermal";
+ match "notify" "0xcc";
+ action "logger -p kern.emerg 'WARNING: system temperature too high, shutting down soon!'";
+};
diff --git a/src/etc/dh-parameters.1024 b/src/etc/dh-parameters.1024
new file mode 100644
index 0000000..3148f4c
--- /dev/null
+++ b/src/etc/dh-parameters.1024
@@ -0,0 +1,5 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAINPWm4z+KHppuzSZFjreaLrKdI/wkP0ojutrSlkiszXsGkbU6++GB1C
+7ZH2ZVpSIo4z31XyQnlraIkyY2pAItxqN8ozWaz84QLSHcwVcWKDEU7ZP0ISyTep
+alnFPGG8nJBSzxch+7H3HOfM68y6kfMtFDWuZtYj/9Zw4W42fVDLAgEC
+-----END DH PARAMETERS-----
diff --git a/src/etc/dh-parameters.2048 b/src/etc/dh-parameters.2048
new file mode 100644
index 0000000..f0e1a5d
--- /dev/null
+++ b/src/etc/dh-parameters.2048
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEAmWwXhRjeqPYl1TvXeKZt5W8MHe0keJK7wC+uPMxpGFVXlvPnWdN+
+W/GyimtD2rHYWF1gyr5IbhiEkXSAuTCnwokwz9XiNQ3hKY/iwTPDo0Go8beB5Ezr
+wz8DibSIv93Va5C+fHzwosuwTAqaOgpOzPqSmVS/UmUATssxOuCK6Crv7YyA5knW
+v0JsJK3VfloeXq/p4skn/KRgL2twO5puJvZWGycMd3cv9+afsWjES/ItwzEHNSEG
+sPen/kNDB4nH+WFKdXnP3fUAqPZCxiqaBC+UnuHngm7Se4smc7DeJkUsed7NLIeg
+zDZ0a3bKZ3UB0lcLGbqXIhh74TtFQ1egmwIBAg==
+-----END DH PARAMETERS-----
diff --git a/src/etc/dh-parameters.4096 b/src/etc/dh-parameters.4096
new file mode 100644
index 0000000..30058a1
--- /dev/null
+++ b/src/etc/dh-parameters.4096
@@ -0,0 +1,13 @@
+-----BEGIN DH PARAMETERS-----
+MIICCAKCAgEA1G0VaCFVkFFPB0pL1Y6NtAlysfvZaAXXmmJ89Xy5wrNLEZfTdmqT
+NmABAhr0DD6+1rcI5d4LriRLhTFf77COjW/+FelEA5BZBsoQDL6QsxWt4VoLT6uK
+bKVkbtwKycz0uOU1areS5gWHF71KRmKgooOuY2yl7a75uLn4QYCS7hKLXsAIB8eC
+63nl81T5gXOAc3hMiKrk8hKLUA6zkMfqWIpG06wvicaPlg8GyQavwGxONDNl/Y2r
+XyRoh/4ja7Moz0tUCmZV+iKtGgq5wekJ1fCN3zhXPX6h6WujoYqzcCmPLFCuIuEa
+kxRy9XaDTe8V40p1RDc4yMYQrl2hxrO8YPRBewigILYxEfe+51qE5Sb//UZszwNL
+kIhW9ObfAkotXoH81xke4EN0RX+rVK1ZYbeBIDCn62ZqNsUVkMh5Otsh0TiK7SP9
+O14IflklQqpyYc+aHMNknhsN30MFV3aD/785QS8zcWUdSdQeZlbjjFgJ4Xpt+r3p
+X6Vv8cwEh8qDHn2CaOfZtyTx2V3B2LU1sJZQ9ynVzlxy2clQcVboXPM1xNgzHSsd
+bFgPMJUAq9VjLGrbN6a3NqWwXnQPMuczX1G3T690fKF55e/boIAXZD1hEZqKt1f0
+DuCwyf/D4CEGyHhHIdVm7f1kTaErWzSgqcc2wGsjFi3ABTG2byxTnSsCAQI=
+-----END DH PARAMETERS-----
diff --git a/src/etc/disktab b/src/etc/disktab
new file mode 100644
index 0000000..5726c4d
--- /dev/null
+++ b/src/etc/disktab
@@ -0,0 +1,204 @@
+# $FreeBSD: stable/10/etc/disktab 242462 2012-11-02 00:17:30Z eadler $
+#
+# Disk geometry and partition layout tables.
+# See disktab(5) for format of this file.
+#
+
+#
+# Floppy formats:
+#
+# To make a filesystem on a floppy:
+# fdformat [-f <size>] fd<drive>[.<size>]
+# disklabel -B -r -w fd<drive>[.<size>] fd<size>
+# newfs <opts> fd<drive>[.<size>]
+#
+# with <opts>:
+# -t 2 - two heads
+# -u 9|15|18 - sectors per track
+# (using the default value of 1/4096 is not much useful for floppies)
+# -l 1 - interleave 1 (for most floppies)
+# -i 65536 - bytes of data per i-node
+# (the default -i value will render you with a floppy wasting way
+# too much space in i-node areas)
+#
+
+fd360:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#9:nc#40:\
+ :pa#720:oa#0:ba#4096:fa#512:\
+ :pc#720:oc#0:bc#4096:fc#512:
+
+fd720:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#9:nc#80:\
+ :pa#1440:oa#0:ba#4096:fa#512:\
+ :pc#1440:oc#0:bc#4096:fc#512:
+
+fd1200|floppy5|5in|5.25in High Density Floppy:\
+ :ty=floppy:se#512:nt#2:rm#360:ns#15:nc#80:\
+ :pa#2400:oa#0:ba#4096:fa#512:\
+ :pc#2400:oc#0:bc#4096:fc#512:
+
+fd1440|floppy|floppy3|3in|3.5in High Density Floppy:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#18:nc#80:\
+ :pa#2880:oa#0:ba#4096:fa#512:\
+ :pc#2880:oc#0:bc#4096:fc#512:
+
+fd2880|2.88MB 3.5in Extra High Density Floppy:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#36:nc#80:\
+ :pa#5760:oa#0:ba#4096:fa#512:\
+ :pb#5760:ob#0:bb#4096:fa#512:\
+ :pc#5760:oc#0:bb#4096:fa#512:
+
+#
+# Stressed floppy-formats. No guarantees given.
+#
+
+fd800:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#10:nc#80:\
+ :pa#1600:oa#0:ba#4096:fa#512:\
+ :pc#1600:oc#0:bc#4096:fc#512:
+
+fd820:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#10:nc#82:\
+ :pa#1640:oa#0:ba#4096:fa#512:\
+ :pc#1640:oc#0:bc#4096:fc#512:
+
+fd1480:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#18:nc#82:\
+ :pa#2952:oa#0:ba#4096:fa#512:\
+ :pc#2952:oc#0:bc#4096:fc#512:
+
+fd1720:\
+ :ty=floppy:se#512:nt#2:rm#300:ns#21:nc#82:\
+ :pa#3444:oa#0:ba#4096:fa#512:\
+ :pc#3444:oc#0:bc#4096:fc#512:
+
+#
+# LS-120 floppy-format.
+#
+fd120m|floppy120|floppy120m|3.5in LS-120 Floppy:\
+ :ty=floppy:se#512:nt#8:rm#300:ns#32:nc#963:\
+ :pa#246528:oa#0:ba#4096:fa#512:\
+ :pc#246528:oc#0:bc#4096:fc#512:
+
+#
+# Harddisk formats
+#
+qp120at|Quantum Peripherals 120MB IDE:\
+ :dt=ESDI:ty=winchester:se#512:nt#9:ns#32:nc#813:sf: \
+ :pa#13824:oa#0:ta=4.2BSD:ba#4096:fa#512: \
+ :pb#13824:ob#13824:tb=swap: \
+ :pc#234144:oc#0: \
+ :ph#206496:oh#27648:th=4.2BSD:bh#4096:fh#512:
+
+pan60|Panasonic Laptop's 60MB IDE:\
+ :dt=ST506:ty=winchester:se#512:nt#13:ns#17:nc#565:\
+ :pa#13260:oa#0:ta=4.2BSD:ba#4096:fa#512:\
+ :pb#13260:ob#13260:tb=swap: \
+ :pc#124865:oc#0: \
+ :ph#97682:oh#26520:th=4.2BSD:bh#4096:fh#512:
+
+mk156|toshiba156|Toshiba MK156 156Mb:\
+ :dt=SCSI:ty=winchester:se#512:nt#10:ns#35:nc#825:\
+ :pa#15748:oa#0:ba#4096:fa#512:ta=4.2BSD:\
+ :pb#15748:ob#15748:tb=swap:\
+ :pc#288750:oc#0:\
+ :ph#257250:oh#31500:bh#4096:fh#512:th=4.2BSD:
+
+cp3100|Connor Peripherals 100MB IDE:\
+ :dt=ST506:ty=winchester:se#512:nt#8:ns#33:nc#766: \
+ :pa#12144:oa#0:ta=4.2BSD:ba#4096:fa#512: \
+ :pb#12144:ob#12144:tb=swap: \
+ :pc#202224:oc#0: \
+ :ph#177936:oh#24288:th=4.2BSD:bh#4096:fh#512:
+
+# a == root
+# b == swap
+# c == d == whole disk
+# e == /var
+# f == scratch
+# h == /usr
+
+cp3100new|Connor Peripherals 100MB IDE, with a different configuration:\
+ :dt=ST506:ty=winchester:se#512:nt#8:ns#33:nc#766: \
+ :pa#15840:oa#0:ta=4.2BSD:ba#4096:fa#512: \
+ :pb#24288:ob#15840:tb=swap: \
+ :pc#202224:oc#0: \
+ :pd#202224:od#0: \
+ :pe#15840:oe#40128:te=4.2BSD:be#4096:fe#512: \
+ :pg#15840:og#55968:tg=4.2BSD:bg#4096:fg#512: \
+ :ph#130416:oh#71808:th=4.2BSD:bh#4096:fh#512:
+
+maxtor4380|Maxtor XT4380E ESDI :\
+ :dt=ESDI:ty=winchester:se#512:nt#15:ns#36:nc#1222:sf: \
+ :pa#21600:oa#0:ta=4.2BSD:ba#4096:fa#512:\
+ :pb#21600:ob#21600:tb=swap: \
+ :pc#659880:oc#0: \
+ :pd#216000:od#53200:td=4.2BSD:bd#4096:fd#512: \
+ :ph#398520:oh#269200:th=4.2BSD:bh#4096:fh#512:
+
+miniscribe9380|compaq38|Miniscribe 9380 ESDI :\
+ :ty=winchester:dt=ESDI:se#512:nt#15:ns#35:nc#1223:rm#3600:sf: \
+ :pa#21000:oa#0:ba#8192:fa#1024:ta=4.2BSD: \
+ :pb#42000:ob#21000:tb=swap: \
+ :pc#642075:oc#0: \
+ :pd#21000:od#63000:bd#8192:fd#1024:td=4.2BSD: \
+ :ph#556500:oh#84000:bh#8192:fh#1024:th=4.2BSD:
+
+ida4|compaq88|Compaq IDA (4 drives) :\
+ :ty=winchester:dt=IDA:se#512:nt#16:ns#63:nc#1644:rm#3600:\
+ :pa#20160:oa#0:ba#8192:fa#1024:ta=4.2BSD: \
+ :pb#80640:ob#20160:tb=swap: \
+ :pc#1659168:oc#0: \
+ :pd#201600:od#100800:bd#8192:fd#1024:td=4.2BSD: \
+ :pe#20160:oe#1310400:be#8192:fe#1024:te=4.2BSD: \
+ :ph#1008000:oh#302400:bh#8192:fh#1024:th=4.2BSD: \
+ :pg#302400:og#1330560:bg#4096:fg#512:tg=4.2BSD:
+
+fuji513|Fujitsu M22XXXX: \
+ :ty=winchester:dt=ESDI:se#512:nt#16:ns#63:nc#954:rm#3600:\
+ :pa#20160:oa#82656:ba#4096:fa#512:ta=4.2BSD: \
+ :pb#40320:ob#102816:tb=swap: \
+ :pc#961632:oc#0: \
+ :ph#656208:oh#143136:bh#4096:fh#512:th=4.2BSD:
+
+sony650|Sony 650 MB MOD|\
+ :ty=removable:dt=SCSI:se#512:nt#1:ns#31:nc#18600:ts#1:rm#4800:\
+ :pc#576600:oc#0:\
+ :pa#576600:oa#0:ta=4.2BSD:ba#8192:fa#1024:
+
+mta3230|mo230|IBM MTA-3230 230 Meg 3.5inch Magneto-Optical:\
+ :ty=removeable:dt=SCSI:rm#3600:\
+ :se#512:nt#64:ns#32:nc#216:sc#2048:su#444384:\
+ :pa#444384:oa#0:ba#4096:fa#0:ta=4.2BSD:\
+ :pc#444384:oc#0:
+
+minimum:ty=mfs:se#512:nt#1:rm#300:\
+ :ns#2880:nc#1:\
+ :pa#2880:oa#0:ba#4096:fa#512:\
+ :pc#2880:oc#0:bc#4096:fc#512:
+
+minimum2:ty=mfs:se#512:nt#1:rm#300:\
+ :ns#5760:nc#1:\
+ :pa#5760:oa#0:ba#4096:fa#512:\
+ :pc#5760:oc#0:bc#4096:fc#512:
+
+minimum3:ty=mfs:se#512:nt#1:rm#300:\
+ :ns#8640:nc#1:\
+ :pa#8640:oa#0:ba#4096:fa#512:\
+ :pc#8640:oc#0:bc#4096:fc#512:
+
+zip100|zip 100:\
+ :ty=removable:se#512:nc#96:nt#64:ns#32:\
+ :pa#196608:oa#0:ba#4096:fa#512:\
+ :pc#196608:oc#0:bc#4096:fc#512:
+
+zip250|zip 250:\
+ :ty=removable:se#512:nc#239:nt#64:ns#32:\
+ :pa#489472:oa#0:ba#4096:fa#512:\
+ :pc#489472:oc#0:bc#4096:fc#512:
+
+orb2200|orb22|orb:\
+ :ty=removable:ns#63:nt#128:nc#4273:sc#1008:su#4307184:se#512:\
+ :pa#4307184:oa#0:ba#8192:fa#1024:\
+ :pc#4307184:oc#0:bc#8192:fc#1024:
+
diff --git a/src/etc/ecl.php b/src/etc/ecl.php
new file mode 100755
index 0000000..15205f1
--- /dev/null
+++ b/src/etc/ecl.php
@@ -0,0 +1,189 @@
+<?php
+/*
+ external config loader
+ Copyright (C) 2010 Scott Ullrich
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ Currently supported file system types: MS-Dos, FreeBSD UFS
+
+*/
+
+require_once("globals.inc");
+require_once("functions.inc");
+require_once("config.lib.inc");
+require_once("config.inc");
+
+$debug = false;
+
+function get_boot_disk() {
+ global $g, $debug;
+ $disk = exec("/sbin/mount | /usr/bin/grep \"on / \" | /usr/bin/cut -d'/' -f3 | /usr/bin/cut -d' ' -f1");
+ return $disk;
+}
+
+function get_swap_disks() {
+ exec("/usr/sbin/swapinfo | /usr/bin/sed '/^\/dev/!d; s,^/dev/,,; s, .*\$,,'", $disks);
+ return $disks;
+}
+
+function get_disk_slices($disk) {
+ global $g, $debug;
+ $slices_array = array();
+ $slices = trim(exec("/bin/ls " . escapeshellarg("/dev/" . $disk . "s*") . " 2>/dev/null"));
+ $slices = str_replace("/dev/", "", $slices);
+ if ($slices == "ls: No match.") {
+ return;
+ }
+ $slices_array = explode(" ", $slices);
+ return $slices_array;
+}
+
+function get_disks() {
+ global $g, $debug;
+ $disks_array = array();
+ $disks_s = explode(" ", get_single_sysctl("kern.disks"));
+ foreach ($disks_s as $disk) {
+ if (trim($disk)) {
+ $disks_array[] = $disk;
+ }
+ }
+ return $disks_array;
+}
+
+function discover_config($mountpoint) {
+ global $g, $debug;
+ $locations_to_check = array("/", "/config");
+ foreach ($locations_to_check as $ltc) {
+ $tocheck = "/tmp/mnt/cf{$ltc}config.xml";
+ if ($debug) {
+ echo "\nChecking for $tocheck";
+ if (file_exists($tocheck)) {
+ echo " -> found!";
+ }
+ }
+ if (file_exists($tocheck)) {
+ return $tocheck;
+ }
+ }
+ return "";
+}
+
+function test_config($file_location) {
+ global $g, $debug;
+ if (!$file_location) {
+ return;
+ }
+ // config.xml was found. ensure it is sound.
+ $root_obj = trim("<{$g['xml_rootobj']}>");
+ $xml_file_head = exec("/usr/bin/head -2 " . escapeshellarg($file_location) . " | /usr/bin/tail -n1");
+ if ($debug) {
+ echo "\nroot obj = $root_obj";
+ echo "\nfile head = $xml_file_head";
+ }
+ if ($xml_file_head == $root_obj) {
+ // Now parse config to make sure
+ $config_status = config_validate($file_location);
+ if ($config_status) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Probes all disks looking for config.xml
+function find_config_xml() {
+ global $g, $debug;
+ $disks = get_disks();
+ // Safety check.
+ if (!is_array($disks)) {
+ return;
+ }
+ $boot_disk = get_boot_disk();
+ $swap_disks = get_swap_disks();
+ exec("/bin/mkdir -p /tmp/mnt/cf");
+ foreach ($disks as $disk) {
+ $slices = get_disk_slices($disk);
+ if (is_array($slices)) {
+ foreach ($slices as $slice) {
+ if ($slice == "") {
+ continue;
+ }
+ if (stristr($slice, $boot_disk)) {
+ if ($debug) {
+ echo "\nSkipping boot device slice $slice";
+ }
+ continue;
+ }
+ if (in_array($slice, $swap_disks)) {
+ if ($debug) {
+ echo "\nSkipping swap device slice $slice";
+ }
+ continue;
+ }
+ echo " $slice";
+ // First try msdos fs
+ if ($debug) {
+ echo "\n/sbin/mount -t msdosfs /dev/{$slice} /tmp/mnt/cf 2>/dev/null \n";
+ }
+ $result = exec("/sbin/mount -t msdosfs /dev/{$slice} /tmp/mnt/cf 2>/dev/null");
+ // Next try regular fs (ufs)
+ if (!$result) {
+ if ($debug) {
+ echo "\n/sbin/mount /dev/{$slice} /tmp/mnt/cf 2>/dev/null \n";
+ }
+ $result = exec("/sbin/mount /dev/{$slice} /tmp/mnt/cf 2>/dev/null");
+ }
+ $mounted = trim(exec("/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep '/tmp/mnt/cf' | /usr/bin/wc -l"));
+ if ($debug) {
+ echo "\nmounted: $mounted ";
+ }
+ if (intval($mounted) > 0) {
+ // Item was mounted - look for config.xml file
+ $config_location = discover_config($slice);
+ if ($config_location) {
+ if (test_config($config_location)) {
+ // We have a valid configuration. Install it.
+ echo " -> found config.xml\n";
+ echo "Backing up old configuration...\n";
+ backup_config();
+ echo "Restoring [{$slice}] {$config_location}...\n";
+ restore_backup($config_location);
+ echo "Cleaning up...\n";
+ exec("/sbin/umount /tmp/mnt/cf");
+ exit;
+ }
+ }
+ exec("/sbin/umount /tmp/mnt/cf");
+ }
+ }
+ }
+ }
+}
+
+echo "External config loader 1.0 is now starting...";
+find_config_xml();
+echo "\n";
+
+?>
diff --git a/src/etc/fbtab b/src/etc/fbtab
new file mode 100644
index 0000000..06d2d61
--- /dev/null
+++ b/src/etc/fbtab
@@ -0,0 +1,4 @@
+# $FreeBSD: src/etc/fbtab,v 1.3 1999/09/13 17:09:07 peter Exp $
+#
+#/dev/ttyv0 0600 /dev/console
+#/dev/ttyv0 0600 /dev/pcaudio:/dev/pcaudioctl
diff --git a/src/etc/gettytab b/src/etc/gettytab
new file mode 100644
index 0000000..5af5aae
--- /dev/null
+++ b/src/etc/gettytab
@@ -0,0 +1,235 @@
+# $FreeBSD: stable/10/etc/gettytab 241708 2012-10-18 22:20:02Z peterj $
+# from: @(#)gettytab 5.14 (Berkeley) 3/27/91
+#
+# Most of the table entries here are just copies of the old getty table,
+# it is by no means certain, or even likely, that any of them are optimal
+# for any purpose whatever. Nor is it likely that more than a couple are
+# even correct.
+#
+# The default gettytab entry, used to set defaults for all other
+# entries, and in cases where getty is called with no table name.
+#
+# cb, ce and ck are desirable on most crt's. The non-crt entries need to
+# be changed to turn them off (:cb@:ce@:ck@:).
+#
+# lc should always be on; it's a remainder of some stone age when there
+# have been terminals around not being able of handling lower-case
+# characters. Those terminals aren't supported any longer, but getty is
+# `smart' about them by default.
+#
+# Parity defaults to even, but the Pc entry and all the `std' entries
+# specify no parity. The different parities are:
+# (none): same as ep for getty. login will use terminal as is.
+# ep: getty will use raw mode (cs8 -parenb) (unless rw is set) and
+# fake parity. login will use even parity (cs7 parenb -parodd).
+# op: same as ep except odd parity (cs7 parenb parodd) for login.
+# getty will fake odd parity as well.
+# ap: same as ep except -inpck instead of inpck for login.
+# ap overrides op and ep.
+# np: 1. don't fake parity in getty. The fake parity garbles
+# characters on non-terminals (like pccons) that don't
+# support parity. It would probably better for getty not to
+# try to fake parity. It could just use cbreak mode so as
+# not to force cs8 and let the hardware handle the parity.
+# login has to be rely on the hardware anyway.
+# 2. set cs8 -parenb -istrip -inpck.
+# ep:op: same as ap.
+#
+default:\
+ :cb:ce:ck:lc:fd#1000:im=\r\n%s/%m (%h) (%t)\r\n\r\n:sp#1200:\
+ :if=/etc/issue:
+
+#
+# Fixed speed entries
+#
+# The "std.NNN" names are known to the special case
+# portselector code in getty, however they can
+# be assigned to any table desired.
+# The "NNN-baud" names are known to the special case
+# autobaud code in getty, and likewise can
+# be assigned to any table desired (hopefully the same speed).
+#
+a|std.110|110-baud:\
+ :np:nd#1:cd#1:uc:sp#110:
+b|std.134|134.5-baud:\
+ :np:nd#1:cd#2:ff#1:td#1:sp#134:ht:nl:
+1|std.150|150-baud:\
+ :np:nd#1:cd#2:td#1:fd#1:sp#150:ht:nl:lm=\E\72\6\6\17login\72 :
+c|std.300|300-baud:\
+ :np:nd#1:cd#1:sp#300:
+d|std.600|600-baud:\
+ :np:nd#1:cd#1:sp#600:
+f|std.1200|1200-baud:\
+ :np:fd#1:sp#1200:
+6|std.2400|2400-baud:\
+ :np:sp#2400:
+7|std.4800|4800-baud:\
+ :np:sp#4800:
+2|std.9600|9600-baud:\
+ :np:sp#9600:
+g|std.19200|19200-baud:\
+ :np:sp#19200:
+std.38400|38400-baud:\
+ :np:sp#38400:
+std.57600|57600-baud:\
+ :np:sp#57600:
+std.115200|115200-baud:\
+ :np:sp#115200:
+std.230400|230400-baud:\
+ :np:sp#230400:
+
+#
+# Entry specifying explicit device settings. See termios(4) and
+# /usr/include/termios.h, too. The entry forces the tty into
+# CLOCAL mode (so no DCD is required), and uses Xon/Xoff flow control.
+#
+# cflags: CLOCAL | HUPCL | CREAD | CS8
+# oflags: OPOST | ONLCR | OXTABS
+# iflags: IXOFF | IXON | ICRNL | IGNPAR
+# lflags: IEXTEN | ICANON | ISIG | ECHOCTL | ECHO | ECHOK | ECHOE | ECHOKE
+#
+# The `0' flags don't have input enabled. The `1' flags don't echo.
+# (Echoing is done inside getty itself.)
+#
+local.9600|CLOCAL tty @ 9600 Bd:\
+ :c0#0x0000c300:c1#0x0000cb00:c2#0x0000cb00:\
+ :o0#0x00000007:o1#0x00000002:o2#0x00000007:\
+ :i0#0x00000704:i1#0x00000000:i2#0x00000704:\
+ :l0#0x000005cf:l1#0x00000000:l2#0x000005cf:\
+ :sp#9600:np:
+
+#
+# Dial in rotary tables, speed selection via 'break'
+#
+0|d300|Dial-300:\
+ :nx=d1200:cd#2:sp#300:
+d1200|Dial-1200:\
+ :nx=d150:fd#1:sp#1200:
+d150|Dial-150:\
+ :nx=d110:lm@:tc=150-baud:
+d110|Dial-110:\
+ :nx=d300:tc=300-baud:
+
+#
+# Fast dialup terminals, 2400/1200/300 rotary (can start either way)
+#
+D2400|d2400|Fast-Dial-2400:\
+ :nx=D1200:tc=2400-baud:
+3|D1200|Fast-Dial-1200:\
+ :nx=D300:tc=1200-baud:
+5|D300|Fast-Dial-300:\
+ :nx=D2400:tc=300-baud:
+
+#
+#telebit (19200)
+#
+t19200:\
+ :nx=t2400:tc=19200-baud:
+t2400:\
+ :nx=t1200:tc=2400-baud:
+t1200:\
+ :nx=t19200:tc=1200-baud:
+
+#
+#telebit (9600)
+#
+t9600:\
+ :nx=t2400a:tc=9600-baud:
+t2400a:\
+ :nx=t1200a:tc=2400-baud:
+t1200a:\
+ :nx=t9600:tc=1200-baud:
+
+#
+# Odd special case terminals
+#
+-|tty33|asr33|Pity the poor user of this beast:\
+ :tc=110-baud:
+
+4|Console|Console Decwriter II:\
+ :nd@:cd@:rw:tc=300-baud:
+
+e|Console-1200|Console Decwriter III:\
+ :fd@:nd@:cd@:rw:tc=1200-baud:
+
+i|Interdata console:\
+ :uc:sp#0:
+
+l|lsi chess terminal:\
+ :sp#300:
+
+X|Xwindow|X window system:\
+ :fd@:nd@:cd@:rw:sp#9600:
+
+P|Pc|Pc console:\
+ :ht:np:sp#9600:
+
+al.Pc:\
+ :ht:np:sp#9600:al=root:
+
+# Weirdo special case for fast crt's with hardcopy devices
+#
+8|T9600|CRT with hardcopy:\
+ :nx=T300:tc=9600-baud:
+9|T300|CRT with hardcopy (300):\
+ :nx=T9600:tc=300-baud:
+
+#
+# Plugboard, and misc other terminals
+#
+plug-9600|Plugboard-9600:\
+ :pf#1:tc=9600-baud:
+p|P9600|Plugboard-9600-rotary:\
+ :pf#1:nx=P300:tc=9600-baud:
+q|P300|Plugboard-300:\
+ :pf#1:nx=P1200:tc=300-baud:
+r|P1200|Plugboard-1200:\
+ :pf#1:nx=P9600:tc=1200-baud:
+
+#
+# XXXX Port selector
+#
+s|DSW|Port Selector:\
+ :ps:sp#2400:
+
+#
+# Auto-baud speed detect entry for Micom 600.
+# Special code in getty will switch this out
+# to one of the NNN-baud entries.
+#
+A|Auto-baud:\
+ :ab:sp#2400:f0#040:
+
+#
+# autologin - automatically log in as root
+#
+
+autologin|al.9600:\
+ :al=root:tc=std.9600:
+al.19200:\
+ :al=root:tc=std.19200:
+al.38400:\
+ :al=root:tc=std.38400:
+al.57600:\
+ :al=root:tc=std.57600:
+al.115200:\
+ :al=root:tc=std.115200:
+al.230400:\
+ :al=root:tc=std.230400:
+
+#
+# Entries for 3-wire serial terminals. These don't supply carrier, so
+# clocal needs to be set, and crtscts needs to be unset.
+#
+3wire.9600|9600-3wire:\
+ :np:nc:sp#9600:
+3wire.19200|19200-3wire:\
+ :np:nc:sp#19200:
+3wire.38400|38400-3wire:\
+ :np:nc:sp#38400:
+3wire.57600|57600-3wire:\
+ :np:nc:sp#57600:
+3wire.115200|115200-3wire:\
+ :np:nc:sp#115200:
+3wire.230400|230400-3wire:\
+ :np:nc:sp#230400:
diff --git a/src/etc/group b/src/etc/group
new file mode 100644
index 0000000..a0ca8ce
--- /dev/null
+++ b/src/etc/group
@@ -0,0 +1,31 @@
+wheel:*:0:root,admin
+daemon:*:1:daemon
+kmem:*:2:root
+sys:*:3:root
+tty:*:4:root
+operator:*:5:root
+mail:*:6:
+bin:*:7:
+news:*:8:
+man:*:9:
+games:*:13:
+staff:*:20:root
+sshd:*:22:
+smmsp:*:25:
+mailnull:*:26:
+guest:*:31:root
+bind:*:53:
+unbound:*:59:
+proxy:*:62:
+_pflogd:*:64:
+_dhcp:*:65:
+authpf:*:63:
+uucp:*:66:
+dialer:*:68:
+network:*:69:
+www:*:80:
+nogroup:*:65533:
+nobody:*:65534:
+audit:*:77:
+_ntp:*:123:
+_relayd:*:913:
diff --git a/src/etc/host.conf b/src/etc/host.conf
new file mode 100644
index 0000000..6643c7f
--- /dev/null
+++ b/src/etc/host.conf
@@ -0,0 +1,7 @@
+# $FreeBSD: src/etc/host.conf,v 1.6 1999/08/27 23:23:41 peter Exp $
+# First try the /etc/hosts file
+hosts
+# Now try the nameserver next.
+bind
+# If you have YP/NIS configured, uncomment the next line
+# nis
diff --git a/src/etc/hosts.allow b/src/etc/hosts.allow
new file mode 100644
index 0000000..ab11cc0
--- /dev/null
+++ b/src/etc/hosts.allow
@@ -0,0 +1,5 @@
+#
+# hosts.allow access control file for "tcp wrapped" applications.
+#
+ALL : ALL : allow
+
diff --git a/src/etc/inc/CHAP.inc b/src/etc/inc/CHAP.inc
new file mode 100644
index 0000000..6eb22f7
--- /dev/null
+++ b/src/etc/inc/CHAP.inc
@@ -0,0 +1,463 @@
+<?php
+/*
+Copyright (c) 2002-2010, Michael Bretterklieber <michael@bretterklieber.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This code cannot simply be copied and put under the GNU Public License or
+any other GPL-like (LGPL, GPL2) License.
+
+ $Id: CHAP.php 302857 2010-08-28 21:12:59Z mbretter $
+*/
+
+require_once 'PEAR.inc';
+
+/**
+* Classes for generating packets for various CHAP Protocols:
+* CHAP-MD5: RFC1994
+* MS-CHAPv1: RFC2433
+* MS-CHAPv2: RFC2759
+*
+* @package Crypt_CHAP
+* @author Michael Bretterklieber <michael@bretterklieber.com>
+* @access public
+* @version $Revision: 302857 $
+*/
+
+/**
+ * class Crypt_CHAP
+ *
+ * Abstract base class for CHAP
+ *
+ * @package Crypt_CHAP
+ */
+class Crypt_CHAP extends PEAR
+{
+ /**
+ * Random binary challenge
+ * @var string
+ */
+ var $challenge = null;
+
+ /**
+ * Binary response
+ * @var string
+ */
+ var $response = null;
+
+ /**
+ * User password
+ * @var string
+ */
+ var $password = null;
+
+ /**
+ * Id of the authentication request. Should incremented after every request.
+ * @var integer
+ */
+ var $chapid = 1;
+
+ /**
+ * Constructor
+ *
+ * Generates a random challenge
+ * @return void
+ */
+ function Crypt_CHAP()
+ {
+ $this->PEAR();
+ $this->generateChallenge();
+ }
+
+ /**
+ * Generates a random binary challenge
+ *
+ * @param string $varname Name of the property
+ * @param integer $size Size of the challenge in Bytes
+ * @return void
+ */
+ function generateChallenge($varname = 'challenge', $size = 8)
+ {
+ $this->$varname = '';
+ for ($i = 0; $i < $size; $i++) {
+ $this->$varname .= pack('C', 1 + mt_rand() % 255);
+ }
+ return $this->$varname;
+ }
+
+ /**
+ * Generates the response. Overwrite this.
+ *
+ * @return void
+ */
+ function challengeResponse()
+ {
+ }
+
+}
+
+/**
+ * class Crypt_CHAP_MD5
+ *
+ * Generate CHAP-MD5 Packets
+ *
+ * @package Crypt_CHAP
+ */
+class Crypt_CHAP_MD5 extends Crypt_CHAP
+{
+
+ /**
+ * Generates the response.
+ *
+ * CHAP-MD5 uses MD5-Hash for generating the response. The Hash consists
+ * of the chapid, the plaintext password and the challenge.
+ *
+ * @return string
+ */
+ function challengeResponse()
+ {
+ return pack('H*', md5(pack('C', $this->chapid) . $this->password . $this->challenge));
+ }
+}
+
+/**
+ * class Crypt_CHAP_MSv1
+ *
+ * Generate MS-CHAPv1 Packets. MS-CHAP doesen't use the plaintext password, it uses the
+ * NT-HASH wich is stored in the SAM-Database or in the smbpasswd, if you are using samba.
+ * The NT-HASH is MD4(str2unicode(plaintextpass)).
+ * You need the hash extension for this class.
+ *
+ * @package Crypt_CHAP
+ */
+class Crypt_CHAP_MSv1 extends Crypt_CHAP
+{
+ /**
+ * Wether using deprecated LM-Responses or not.
+ * 0 = use LM-Response, 1 = use NT-Response
+ * @var bool
+ */
+ var $flags = 1;
+
+ /**
+ * Constructor
+ *
+ * Loads the hash extension
+ * @return void
+ */
+ function Crypt_CHAP_MSv1()
+ {
+ $this->Crypt_CHAP();
+ $this->loadExtension('hash');
+ }
+
+ /**
+ * Generates the NT-HASH from the given plaintext password.
+ *
+ * @access public
+ * @return string
+ */
+ function ntPasswordHash($password = null)
+ {
+ if (isset($password)) {
+ return pack('H*',hash('md4', $this->str2unicode($password)));
+ } else {
+ return pack('H*',hash('md4', $this->str2unicode($this->password)));
+ }
+ }
+
+ /**
+ * Converts ascii to unicode.
+ *
+ * @access public
+ * @return string
+ */
+ function str2unicode($str)
+ {
+ $uni = '';
+ $str = (string) $str;
+ for ($i = 0; $i < strlen($str); $i++) {
+ $a = ord($str{$i}) << 8;
+ $uni .= sprintf("%X", $a);
+ }
+ return pack('H*', $uni);
+ }
+
+ /**
+ * Generates the NT-Response.
+ *
+ * @access public
+ * @return string
+ */
+ function challengeResponse()
+ {
+ return $this->_challengeResponse();
+ }
+
+ /**
+ * Generates the NT-Response.
+ *
+ * @access public
+ * @return string
+ */
+ function ntChallengeResponse()
+ {
+ return $this->_challengeResponse(false);
+ }
+
+ /**
+ * Generates the LAN-Manager-Response.
+ *
+ * @access public
+ * @return string
+ */
+ function lmChallengeResponse()
+ {
+ return $this->_challengeResponse(true);
+ }
+
+ /**
+ * Generates the response.
+ *
+ * Generates the response using DES.
+ *
+ * @param bool $lm wether generating LAN-Manager-Response
+ * @access private
+ * @return string
+ */
+ function _challengeResponse($lm = false)
+ {
+ if ($lm) {
+ $hash = $this->lmPasswordHash();
+ } else {
+ $hash = $this->ntPasswordHash();
+ }
+
+ while (strlen($hash) < 21) {
+ $hash .= "\0";
+ }
+
+ $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
+ $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
+ $key = $this->_desAddParity(substr($hash, 0, 7));
+ mcrypt_generic_init($td, $key, $iv);
+ $resp1 = mcrypt_generic($td, $this->challenge);
+ mcrypt_generic_deinit($td);
+
+ $key = $this->_desAddParity(substr($hash, 7, 7));
+ mcrypt_generic_init($td, $key, $iv);
+ $resp2 = mcrypt_generic($td, $this->challenge);
+ mcrypt_generic_deinit($td);
+
+ $key = $this->_desAddParity(substr($hash, 14, 7));
+ mcrypt_generic_init($td, $key, $iv);
+ $resp3 = mcrypt_generic($td, $this->challenge);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+
+ return $resp1 . $resp2 . $resp3;
+ }
+
+ /**
+ * Generates the LAN-Manager-HASH from the given plaintext password.
+ *
+ * @access public
+ * @return string
+ */
+ function lmPasswordHash($password = null)
+ {
+ $plain = isset($password) ? $password : $this->password;
+
+ $plain = substr(strtoupper($plain), 0, 14);
+ while (strlen($plain) < 14) {
+ $plain .= "\0";
+ }
+
+ return $this->_desHash(substr($plain, 0, 7)) . $this->_desHash(substr($plain, 7, 7));
+ }
+
+ /**
+ * Generates an irreversible HASH.
+ *
+ * @access private
+ * @return string
+ */
+ function _desHash($plain)
+ {
+ $key = $this->_desAddParity($plain);
+ $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
+ $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
+ mcrypt_generic_init($td, $key, $iv);
+ $hash = mcrypt_generic($td, 'KGS!@#$%');
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ return $hash;
+ }
+
+ /**
+ * Adds the parity bit to the given DES key.
+ *
+ * @access private
+ * @param string $key 7-Bytes Key without parity
+ * @return string
+ */
+ function _desAddParity($key)
+ {
+ static $odd_parity = array(
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+ 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+ 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+ 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+ 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+ 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+ 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+ 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+ 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+ 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254);
+
+ $bin = '';
+ for ($i = 0; $i < strlen($key); $i++) {
+ $bin .= sprintf('%08s', decbin(ord($key{$i})));
+ }
+
+ $str1 = explode('-', substr(chunk_split($bin, 7, '-'), 0, -1));
+ $x = '';
+ foreach($str1 as $s) {
+ $x .= sprintf('%02s', dechex($odd_parity[bindec($s . '0')]));
+ }
+
+ return pack('H*', $x);
+
+ }
+
+ /**
+ * Generates the response-packet.
+ *
+ * @param bool $lm wether including LAN-Manager-Response
+ * @access private
+ * @return string
+ */
+ function response($lm = false)
+ {
+ $ntresp = $this->ntChallengeResponse();
+ if ($lm) {
+ $lmresp = $this->lmChallengeResponse();
+ } else {
+ $lmresp = str_repeat ("\0", 24);
+ }
+
+ // Response: LM Response, NT Response, flags (0 = use LM Response, 1 = use NT Response)
+ return $lmresp . $ntresp . pack('C', !$lm);
+ }
+}
+
+/**
+ * class Crypt_CHAP_MSv2
+ *
+ * Generate MS-CHAPv2 Packets. This version of MS-CHAP uses a 16 Bytes authenticator
+ * challenge and a 16 Bytes peer Challenge. LAN-Manager responses no longer exists
+ * in this version. The challenge is already a SHA1 challenge hash of both challenges
+ * and of the username.
+ *
+ * @package Crypt_CHAP
+ */
+class Crypt_CHAP_MSv2 extends Crypt_CHAP_MSv1
+{
+ /**
+ * The username
+ * @var string
+ */
+ var $username = null;
+
+ /**
+ * The 16 Bytes random binary peer challenge
+ * @var string
+ */
+ var $peerChallenge = null;
+
+ /**
+ * The 16 Bytes random binary authenticator challenge
+ * @var string
+ */
+ var $authChallenge = null;
+
+ /**
+ * Constructor
+ *
+ * Generates the 16 Bytes peer and authentication challenge
+ * @return void
+ */
+ function Crypt_CHAP_MSv2()
+ {
+ $this->Crypt_CHAP_MSv1();
+ $this->generateChallenge('peerChallenge', 16);
+ $this->generateChallenge('authChallenge', 16);
+ }
+
+ /**
+ * Generates a hash from the NT-HASH.
+ *
+ * @access public
+ * @param string $nthash The NT-HASH
+ * @return string
+ */
+ function ntPasswordHashHash($nthash)
+ {
+ return pack('H*',hash('md4', $nthash));
+ }
+
+ /**
+ * Generates the challenge hash from the peer and the authenticator challenge and
+ * the username. SHA1 is used for this, but only the first 8 Bytes are used.
+ *
+ * @access public
+ * @return string
+ */
+ function challengeHash()
+ {
+ return substr(pack('H*',hash('sha1', $this->peerChallenge . $this->authChallenge . $this->username)), 0, 8);
+ }
+
+ /**
+ * Generates the response.
+ *
+ * @access public
+ * @return string
+ */
+ function challengeResponse()
+ {
+ $this->challenge = $this->challengeHash();
+ return $this->_challengeResponse();
+ }
+}
+
+
+?>
diff --git a/src/etc/inc/IPv6.inc b/src/etc/inc/IPv6.inc
new file mode 100644
index 0000000..faacb8d
--- /dev/null
+++ b/src/etc/inc/IPv6.inc
@@ -0,0 +1,1110 @@
+<?php
+
+/*
+ pfSense_MODULE: utils
+*/
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * This file contains the implementation of the Net_IPv6 class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to the New BSD license, that is
+ * available through the world-wide-web at
+ * http://www.opensource.org/licenses/bsd-license.php
+ * If you did not receive a copy of the new BSDlicense and are unable
+ * to obtain it through the world-wide-web, please send a note to
+ * license@php.net so we can mail you a copy immediately
+ *
+ * @category Net
+ * @package Net_IPv6
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @copyright 2003-2005 The PHP Group
+ * @license BSD License http://www.opensource.org/licenses/bsd-license.php
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/Net_IPv6
+ */
+
+// {{{ constants
+
+/**
+ * Error message if netmask bits was not found
+ * @see isInNetmask
+ */
+define("NET_IPV6_NO_NETMASK_MSG", "Netmask length not found");
+
+/**
+ * Error code if netmask bits was not found
+ * @see isInNetmask
+ */
+define("NET_IPV6_NO_NETMASK", 10);
+
+/**
+ * Address Type: Unassigned (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNASSIGNED", 1);
+
+/**
+ * Address Type: Reserved (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED", 11);
+
+/**
+ * Address Type: Reserved for NSAP Allocation (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_NSAP", 12);
+
+/**
+ * Address Type: Reserved for IPX Allocation (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_IPX", 13);
+
+/**
+ * Address Type: Reserved for Geographic-Based Unicast Addresses
+ * (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC", 14);
+
+/**
+ * Address Type: Provider-Based Unicast Address (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNICAST_PROVIDER", 22);
+
+/**
+ * Address Type: Multicast Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_MULTICAST", 31);
+
+/**
+ * Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_LOCAL_LINK", 42);
+
+/**
+ * Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_LOCAL_SITE", 43);
+
+/**
+ * Address Type: Address range to embedded IPv4 ip in an IPv6 address (RFC 4291, Section 2.5.5)
+ * @see getAddressType()
+ */
+define("NET_IPV6_IPV4MAPPING", 51);
+
+/**
+ * Address Type: Unspecified (RFC 4291, Section 2.5.2)
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNSPECIFIED", 52);
+
+/**
+ * Address Type: Unspecified (RFC 4291, Section 2.5.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_LOOPBACK", 53);
+
+/**
+ * Address Type: address can not assigned to a specific type
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNKNOWN_TYPE", 1001);
+
+// }}}
+// {{{ Net_IPv6
+
+/**
+ * Class to validate and to work with IPv6 addresses.
+ *
+ * @category Net
+ * @package Net_IPv6
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @author <elfrink at introweb dot nl>
+ * @author Josh Peck <jmp at joshpeck dot org>
+ * @copyright 2003-2010 The PHP Group
+ * @license BSD License http://www.opensource.org/licenses/bsd-license.php
+ * @version Release: 1.1.0RC5
+ * @link http://pear.php.net/package/Net_IPv6
+ */
+class Net_IPv6
+{
+
+ // {{{ separate()
+ /**
+ * Separates an IPv6 address into the address and a prefix length part
+ *
+ * @param String $ip the (compressed) IP as Hex representation
+ *
+ * @return Array the first element is the IP, the second the prefix length
+ * @since 1.2.0
+ * @access public
+ * @static
+ */
+ static function separate($ip)
+ {
+
+ $addr = $ip;
+ $spec = '';
+
+ if(false === strrpos($ip, '/')) {
+
+ return array($addr, $spec);
+
+ }
+
+ $elements = explode('/', $ip);
+
+ if(2 == count($elements)) {
+
+ $addr = $elements[0];
+ $spec = $elements[1];
+
+ }
+
+ return array($addr, $spec);
+
+ }
+ // }}}
+
+ // {{{ removeNetmaskSpec()
+
+ /**
+ * Removes a possible existing prefix length/ netmask specification at an IP address.
+ *
+ * @param String $ip the (compressed) IP as Hex representation
+ *
+ * @return String the IP without netmask length
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ static function removeNetmaskSpec($ip)
+ {
+
+ $elements = Net_IPv6::separate($ip);
+
+ return $elements[0];
+
+ }
+ // }}}
+ // {{{ removePrefixLength()
+
+ /**
+ * Tests for a prefix length specification in the address
+ * and removes the prefix length, if exists
+ *
+ * The method is technically identical to removeNetmaskSpec() and
+ * will be dropped in a future release.
+ *
+ * @param String $ip a valid ipv6 address
+ *
+ * @return String the address without a prefix length
+ * @access public
+ * @static
+ * @see removeNetmaskSpec()
+ * @deprecated
+ */
+ static function removePrefixLength($ip)
+ {
+ $pos = strrpos($ip, '/');
+
+ if (false !== $pos) {
+
+ return substr($ip, 0, $pos);
+
+ }
+
+ return $ip;
+ }
+
+ // }}}
+ // {{{ getNetmaskSpec()
+
+ /**
+ * Returns a possible existing prefix length/netmask specification on an IP address.
+ *
+ * @param String $ip the (compressed) IP as Hex representation
+ *
+ * @return String the netmask spec
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ static function getNetmaskSpec($ip)
+ {
+
+ $elements = Net_IPv6::separate($ip);
+
+ return $elements[1];
+
+ }
+
+ // }}}
+ // {{{ getPrefixLength()
+
+ /**
+ * Tests for a prefix length specification in the address
+ * and returns the prefix length, if exists
+ *
+ * The method is technically identical to getNetmaskSpec() and
+ * will be dropped in a future release.
+ *
+ * @param String $ip a valid ipv6 address
+ *
+ * @return Mixed the prefix as String or false, if no prefix was found
+ * @access public
+ * @static
+ * @deprecated
+ */
+ static function getPrefixLength($ip)
+ {
+ if (preg_match("/^([0-9a-fA-F:]{2,39})\/(\d{1,3})*$/",
+ $ip, $matches)) {
+
+ return $matches[2];
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ // }}}
+ // {{{ getNetmask()
+
+ /**
+ * Calculates the network prefix based on the netmask bits.
+ *
+ * @param String $ip the (compressed) IP in Hex format
+ * @param int $bits if the number of netmask bits is not part of the IP
+ * you must provide the number of bits
+ *
+ * @return String the network prefix
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ static function getNetmask($ip, $bits = null)
+ {
+ if (null==$bits) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $addr = $elements[0];
+ $bits = $elements[1];
+
+ } else {
+
+ include_once 'PEAR.inc';
+
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+ }
+
+ } else {
+
+ $addr = $ip;
+
+ }
+
+ $addr = Net_IPv6::uncompress($addr);
+ $binNetmask = str_repeat('1', $bits).str_repeat('0', 128 - $bits);
+
+ return Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($addr) & $binNetmask);
+ }
+
+ // }}}
+ // {{{ isInNetmask()
+
+ /**
+ * Checks if an (compressed) IP is in a specific address space.
+ *
+ * If the IP does not contain the number of netmask bits (F8000::FFFF/16)
+ * then you have to use the $bits parameter.
+ *
+ * @param String $ip the IP to check (eg. F800::FFFF)
+ * @param String $netmask the netmask (eg F800::)
+ * @param int $bits the number of netmask bits to compare,
+ * if not given in $ip
+ *
+ * @return boolean true if $ip is in the netmask
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ static function isInNetmask($ip, $netmask, $bits=null)
+ {
+ // try to get the bit count
+
+ if (null == $bits) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $ip = $elements[0];
+ $bits = $elements[1];
+
+ } else if (null == $bits) {
+
+ $elements = explode('/', $netmask);
+
+ if (2 == count($elements)) {
+
+ $netmask = $elements[0];
+ $bits = $elements[1];
+
+ }
+
+ if (null == $bits) {
+
+ include_once 'PEAR.inc';
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+
+ }
+
+ }
+
+ }
+
+ $binIp = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($ip));
+ $binNetmask = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($netmask));
+
+ if (null != $bits
+ && "" != $bits
+ && 0 == strncmp($binNetmask, $binIp, $bits)) {
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+ // }}}
+ // {{{ getAddressType()
+
+ /**
+ * Returns the type of an IPv6 address.
+ *
+ * RFC 2373, Section 2.3 describes several types of addresses in
+ * the IPv6 address space.
+ * Several address types are markers for reserved spaces and as
+ * a consequence are subject to change.
+ *
+ * @param String $ip the IP address in Hex format,
+ * compressed IPs are allowed
+ *
+ * @return int one of the address type constants
+ * @access public
+ * @since 1.1.0
+ * @static
+ *
+ * @see NET_IPV6_UNASSIGNED
+ * @see NET_IPV6_RESERVED
+ * @see NET_IPV6_RESERVED_NSAP
+ * @see NET_IPV6_RESERVED_IPX
+ * @see NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC
+ * @see NET_IPV6_UNICAST_PROVIDER
+ * @see NET_IPV6_MULTICAST
+ * @see NET_IPV6_LOCAL_LINK
+ * @see NET_IPV6_LOCAL_SITE
+ * @see NET_IPV6_IPV4MAPPING
+ * @see NET_IPV6_UNSPECIFIED
+ * @see NET_IPV6_LOOPBACK
+ * @see NET_IPV6_UNKNOWN_TYPE
+ */
+ static function getAddressType($ip)
+ {
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+ $binip = Net_IPv6::_ip2Bin($ip);
+
+ if(0 == strncmp(str_repeat('0', 128), $binip, 128)) { // ::/128
+
+ return NET_IPV6_UNSPECIFIED;
+
+ } else if(0 == strncmp(str_repeat('0', 127).'1', $binip, 128)) { // ::/128
+
+ return NET_IPV6_LOOPBACK;
+
+ } else if (0 == strncmp(str_repeat('0', 80).str_repeat('1', 16), $binip, 96)) { // ::ffff/96
+
+ return NET_IPV6_IPV4MAPPING;
+
+ } else if (0 == strncmp('1111111010', $binip, 10)) {
+
+ return NET_IPV6_LOCAL_LINK;
+
+ } else if (0 == strncmp('1111111011', $binip, 10)) {
+
+ return NET_IPV6_LOCAL_SITE;
+
+ } else if (0 == strncmp('111111100', $binip, 9)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('11111111', $binip, 8)) {
+
+ return NET_IPV6_MULTICAST;
+
+ } else if (0 == strncmp('00000000', $binip, 8)) {
+
+ return NET_IPV6_RESERVED;
+
+ } else if (0 == strncmp('00000001', $binip, 8)
+ || 0 == strncmp('1111110', $binip, 7)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('0000001', $binip, 7)) {
+
+ return NET_IPV6_RESERVED_NSAP;
+
+ } else if (0 == strncmp('0000010', $binip, 7)) {
+
+ return NET_IPV6_RESERVED_IPX;
+
+ } else if (0 == strncmp('0000011', $binip, 7) ||
+ 0 == strncmp('111110', $binip, 6) ||
+ 0 == strncmp('11110', $binip, 5) ||
+ 0 == strncmp('00001', $binip, 5) ||
+ 0 == strncmp('1110', $binip, 4) ||
+ 0 == strncmp('0001', $binip, 4) ||
+ 0 == strncmp('001', $binip, 3) ||
+ 0 == strncmp('011', $binip, 3) ||
+ 0 == strncmp('101', $binip, 3) ||
+ 0 == strncmp('110', $binip, 3)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('010', $binip, 3)) {
+
+ return NET_IPV6_UNICAST_PROVIDER;
+
+ } else if (0 == strncmp('100', $binip, 3)) {
+
+ return NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC;
+
+ }
+
+ return NET_IPV6_UNKNOWN_TYPE;
+ }
+
+ // }}}
+ // {{{ Uncompress()
+
+ /**
+ * Uncompresses an IPv6 address
+ *
+ * RFC 2373 allows you to compress zeros in an address to '::'. This
+ * function expects a valid IPv6 address and expands the '::' to
+ * the required zeros.
+ *
+ * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
+ * ::1 -> 0:0:0:0:0:0:0:1
+ *
+ * Note: You can also pass an invalid IPv6 address (usually as part of the process
+ * of validation by checkIPv6, which will validate the return string).
+ * This function will insert the "0" between "::" even if this results in too many
+ * numbers in total. It is NOT the purpose of this function to validate your input.
+ *
+ * Example of calling with invalid input: 1::2:3:4:5:6:7:8:9 -> 1:0:2:3:4:5:6:7:8:9
+ *
+ * @param String $ip a (possibly) valid IPv6-address (hex format)
+ * @param Boolean $leadingZeros if true, leading zeros are added to each
+ * block of the address
+ * (FF01::101 ->
+ * FF01:0000:0000:0000:0000:0000:0000:0101)
+ *
+ * @return String the uncompressed IPv6-address (hex format)
+ * @access public
+ * @see Compress()
+ * @static
+ * @author Pascal Uhlmann
+ */
+ static function uncompress($ip, $leadingZeros = false)
+ {
+
+ $prefix = Net_IPv6::getPrefixLength($ip);
+
+ if (false === $prefix) {
+
+ $prefix = '';
+
+ } else {
+
+ $ip = Net_IPv6::removePrefixLength($ip);
+ $prefix = '/'.$prefix;
+
+ }
+
+ $netmask = Net_IPv6::getNetmaskSpec($ip);
+ $uip = Net_IPv6::removeNetmaskSpec($ip);
+
+ $c1 = -1;
+ $c2 = -1;
+
+ if (false !== strpos($uip, '::') ) {
+
+ list($ip1, $ip2) = explode('::', $uip);
+
+ if ("" == $ip1) {
+
+ $c1 = -1;
+
+ } else {
+
+ $pos = 0;
+
+ if (0 < ($pos = substr_count($ip1, ':'))) {
+
+ $c1 = $pos;
+
+ } else {
+
+ $c1 = 0;
+
+ }
+ }
+ if ("" == $ip2) {
+
+ $c2 = -1;
+
+ } else {
+
+ $pos = 0;
+
+ if (0 < ($pos = substr_count($ip2, ':'))) {
+
+ $c2 = $pos;
+
+ } else {
+
+ $c2 = 0;
+
+ }
+
+ }
+
+ if (strstr($ip2, '.')) {
+
+ $c2++;
+
+ }
+ if (-1 == $c1 && -1 == $c2) { // ::
+
+ $uip = "0:0:0:0:0:0:0:0";
+
+ } else if (-1 == $c1) { // ::xxx
+
+ $fill = str_repeat('0:', 7-$c2);
+ $uip = str_replace('::', $fill, $uip);
+
+ } else if (-1 == $c2) { // xxx::
+
+ $fill = str_repeat(':0', 7-$c1);
+ $uip = str_replace('::', $fill, $uip);
+
+ } else { // xxx::xxx
+
+ $fill = str_repeat(':0:', max(1, 6-$c2-$c1));
+ $uip = str_replace('::', $fill, $uip);
+ $uip = str_replace('::', ':', $uip);
+
+ }
+ }
+
+ if(true == $leadingZeros) {
+
+ $uipT = array();
+ $uiparts = explode(':', $uip);
+
+ foreach($uiparts as $p) {
+
+ $uipT[] = sprintf('%04s', $p);
+
+ }
+
+ $uip = implode(':', $uipT);
+ }
+
+ if ('' != $netmask) {
+
+ $uip = $uip.'/'.$netmask;
+
+ }
+
+ return $uip.$prefix;
+ }
+
+ // }}}
+ // {{{ Compress()
+
+ /**
+ * Compresses an IPv6 address
+ *
+ * RFC 2373 allows you to compress zeros in an address to '::'. This
+ * function expects a valid IPv6 address and compresses successive zeros
+ * to '::'
+ *
+ * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
+ * 0:0:0:0:0:0:0:1 -> ::1
+ *
+ * When $ip is an already compressed address and $force is false, the method returns
+ * the value as is, even if the address can be compressed further.
+ *
+ * Example: FF01::0:1 -> FF01::0:1
+ *
+ * To enforce maximum compression, you can set the second argument $force to true.
+ *
+ * Example: FF01::0:1 -> FF01::1
+ *
+ * @param String $ip a valid IPv6-address (hex format)
+ * @param boolean $force if true the address will be compressed as best as possible (since 1.2.0)
+ *
+ * @return String the compressed IPv6-address (hex format)
+ * @access public
+ * @see Uncompress()
+ * @static
+ * @author elfrink at introweb dot nl
+ */
+ static function compress($ip, $force = false)
+ {
+
+ if(false !== strpos($ip, '::')) { // its already compressed
+
+ if(true == $force) {
+
+ $ip = Net_IPv6::uncompress($ip);
+
+ } else {
+
+ return $ip;
+
+ }
+
+ }
+
+ $prefix = Net_IPv6::getPrefixLength($ip);
+
+ if (false === $prefix) {
+
+ $prefix = '';
+
+ } else {
+
+ $ip = Net_IPv6::removePrefixLength($ip);
+ $prefix = '/'.$prefix;
+
+ }
+
+ $netmask = Net_IPv6::getNetmaskSpec($ip);
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+
+ $ipp = explode(':', $ip);
+
+ for ($i = 0; $i < count($ipp); $i++) {
+
+ $ipp[$i] = dechex(hexdec($ipp[$i]));
+
+ }
+
+ $cip = ':' . join(':', $ipp) . ':';
+
+ preg_match_all("/(:0)(:0)+/", $cip, $zeros);
+
+ if (count($zeros[0]) > 0) {
+
+ $match = '';
+
+ foreach ($zeros[0] as $zero) {
+
+ if (strlen($zero) > strlen($match)) {
+
+ $match = $zero;
+
+ }
+ }
+
+ $cip = preg_replace('/' . $match . '/', ':', $cip, 1);
+
+ }
+
+ $cip = preg_replace('/((^:)|(:$))/', '', $cip);
+ $cip = preg_replace('/((^:)|(:$))/', '::', $cip);
+
+ if (empty($cip)) {
+
+ $cip = "::";
+
+ }
+
+ if ('' != $netmask) {
+
+ $cip = $cip.'/'.$netmask;
+
+ }
+
+ return $cip.$prefix;
+
+ }
+
+ // }}}
+ // {{{ recommendedFormat()
+ /**
+ * Represent IPv6 address in RFC5952 format.
+ *
+ * @param String $ip a valid IPv6-address (hex format)
+ *
+ * @return String the recommended representation of IPv6-address (hex format)
+ * @access public
+ * @see compress()
+ * @static
+ * @author koyama at hoge dot org
+ * @todo This method may become a part of compress() in a further releases
+ */
+ static function recommendedFormat($ip)
+ {
+ $compressed = self::compress($ip, true);
+ // RFC5952 4.2.2
+ // The symbol "::" MUST NOT be used to shorten just one
+ // 16-bit 0 field.
+ if ((substr_count($compressed, ':') == 7) &&
+ (strpos($compressed, '::') !== false)) {
+ $compressed = str_replace('::', ':0:', $compressed);
+ }
+ return $compressed;
+ }
+ // }}}
+
+ // {{{ isCompressible()
+
+ /**
+ * Checks, if an IPv6 address can be compressed
+ *
+ * @param String $ip a valid IPv6 address
+ *
+ * @return Boolean true, if address can be compressed
+ *
+ * @access public
+ * @since 1.2.0b
+ * @static
+ * @author Manuel Schmitt
+ */
+ static function isCompressible($ip)
+ {
+
+ return (bool)($ip != Net_IPv6::compress($address));
+
+ }
+
+ // }}}
+ // {{{ SplitV64()
+
+ /**
+ * Splits an IPv6 address into the IPv6 and a possible IPv4 part
+ *
+ * RFC 2373 allows you to note the last two parts of an IPv6 address as
+ * an IPv4 compatible address
+ *
+ * Example: 0:0:0:0:0:0:13.1.68.3
+ * 0:0:0:0:0:FFFF:129.144.52.38
+ *
+ * @param String $ip a valid IPv6-address (hex format)
+ * @param Boolean $uncompress if true, the address will be uncompressed
+ * before processing
+ *
+ * @return Array [0] contains the IPv6 part,
+ * [1] the IPv4 part (hex format)
+ * @access public
+ * @static
+ */
+ static function SplitV64($ip, $uncompress = true)
+ {
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+
+ if ($uncompress) {
+
+ $ip = Net_IPv6::Uncompress($ip);
+
+ }
+
+ if (strstr($ip, '.')) {
+
+ $pos = strrpos($ip, ':');
+ $ip{$pos} = '_';
+ $ipPart = explode('_', $ip);
+
+ return $ipPart;
+
+ } else {
+
+ return array($ip, "");
+
+ }
+ }
+
+ // }}}
+ // {{{ checkIPv6()
+
+ /**
+ * Checks an IPv6 address
+ *
+ * Checks if the given IP is IPv6-compatible
+ *
+ * @param String $ip a valid IPv6-address
+ *
+ * @return Boolean true if $ip is an IPv6 address
+ * @access public
+ * @static
+ */
+ static function checkIPv6($ip)
+ {
+
+ $elements = Net_IPv6::separate($ip);
+
+ $ip = $elements[0];
+
+ if('' != $elements[1] && ( !is_numeric($elements[1]) || 0 > $elements[1] || 128 < $elements[1])) {
+
+ return false;
+
+ }
+
+ $ipPart = Net_IPv6::SplitV64($ip);
+ $count = 0;
+
+ if (!empty($ipPart[0])) {
+ $ipv6 = explode(':', $ipPart[0]);
+
+ foreach($ipv6 as $element) { // made a validate precheck
+ if(!preg_match('/[0-9a-fA-F]*/', $element)) {
+ return false;
+ }
+ }
+
+ for ($i = 0; $i < count($ipv6); $i++) {
+
+ if(4 < strlen($ipv6[$i])) {
+
+ return false;
+
+ }
+
+ $dec = hexdec($ipv6[$i]);
+ $hex = strtoupper(preg_replace("/^[0]{1,3}(.*[0-9a-fA-F])$/",
+ "\\1",
+ $ipv6[$i]));
+
+ if ($ipv6[$i] >= 0 && $dec <= 65535
+ && $hex == strtoupper(dechex($dec))) {
+
+ $count++;
+
+ }
+
+ }
+
+ if (8 == $count) {
+
+ return true;
+
+ } else if (6 == $count and !empty($ipPart[1])) {
+
+ $ipv4 = explode('.', $ipPart[1]);
+ $count = 0;
+
+ for ($i = 0; $i < count($ipv4); $i++) {
+
+ if ($ipv4[$i] >= 0 && (integer)$ipv4[$i] <= 255
+ && preg_match("/^\d{1,3}$/", $ipv4[$i])) {
+
+ $count++;
+
+ }
+
+ }
+
+ if (4 == $count) {
+
+ return true;
+
+ }
+
+ } else {
+
+ return false;
+
+ }
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ // }}}
+
+ // {{{ _parseAddress()
+
+ /**
+ * Returns the lowest and highest IPv6 address
+ * for a given IP and netmask specification
+ *
+ * The netmask may be a part of the $ip or
+ * the number of netmask bits is provided via $bits
+ *
+ * The result is an indexed array. The key 'start'
+ * contains the lowest possible IP address. The key
+ * 'end' the highest address.
+ *
+ * @param String $ipToParse the IPv6 address
+ * @param String $bits the optional count of netmask bits
+ *
+ * @return Array ['start', 'end'] the lowest and highest IPv6 address
+ * @access public
+ * @static
+ * @author Nicholas Williams
+ */
+
+ static function parseAddress($ipToParse, $bits = null)
+ {
+
+ $ip = null;
+ $bitmask = null;
+
+ if ( null == $bits ) {
+
+ $elements = explode('/', $ipToParse);
+
+ if ( 2 == count($elements) ) {
+
+ $ip = Net_IPv6::uncompress($elements[0]);
+ $bitmask = $elements[1];
+
+ } else {
+
+ include_once 'PEAR.inc';
+
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+ }
+ } else {
+
+ $ip = Net_IPv6::uncompress($ipToParse);
+ $bitmask = $bits;
+
+ }
+
+ $binNetmask = str_repeat('1', $bitmask).
+ str_repeat('0', 128 - $bitmask);
+ $maxNetmask = str_repeat('1', 128);
+ $netmask = Net_IPv6::_bin2Ip($binNetmask);
+
+ $startAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip)
+ & $binNetmask);
+ $endAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip)
+ | ($binNetmask ^ $maxNetmask));
+
+ return array('start' => $startAddress, 'end' => $endAddress);
+ }
+
+ // }}}
+
+ // {{{ _ip2Bin()
+
+ /**
+ * Converts an IPv6 address from Hex into Binary representation.
+ *
+ * @param String $ip the IP to convert (a:b:c:d:e:f:g:h),
+ * compressed IPs are allowed
+ *
+ * @return String the binary representation
+ * @access private
+ @ @since 1.1.0
+ */
+ static function _ip2Bin($ip)
+ {
+ $binstr = '';
+
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+ $ip = Net_IPv6::Uncompress($ip);
+
+ $parts = explode(':', $ip);
+
+ foreach ( $parts as $v ) {
+
+ $str = base_convert($v, 16, 2);
+ $binstr .= str_pad($str, 16, '0', STR_PAD_LEFT);
+
+ }
+
+ return $binstr;
+ }
+
+ // }}}
+ // {{{ _bin2Ip()
+
+ /**
+ * Converts an IPv6 address from Binary into Hex representation.
+ *
+ * @param String $bin the IP address as binary
+ *
+ * @return String the uncompressed Hex representation
+ * @access private
+ @ @since 1.1.0
+ */
+ static function _bin2Ip($bin)
+ {
+ $ip = "";
+
+ if (strlen($bin) < 128) {
+
+ $bin = str_pad($bin, 128, '0', STR_PAD_LEFT);
+
+ }
+
+ $parts = str_split($bin, "16");
+
+ foreach ( $parts as $v ) {
+
+ $str = base_convert($v, 2, 16);
+ $ip .= $str.":";
+
+ }
+
+ $ip = substr($ip, 0, -1);
+
+ return $ip;
+ }
+
+ // }}}
+}
+// }}}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?>
diff --git a/src/etc/inc/PEAR.inc b/src/etc/inc/PEAR.inc
new file mode 100644
index 0000000..a280602
--- /dev/null
+++ b/src/etc/inc/PEAR.inc
@@ -0,0 +1,1103 @@
+<?php
+/**
+ * PEAR, the PHP Extension and Application Repository
+ *
+ * PEAR class and PEAR_Error class
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Sterling Hughes <sterling@php.net>
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V.Cox <cox@idecnet.com>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2010 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**#@+
+ * ERROR constants
+ */
+define('PEAR_ERROR_RETURN', 1);
+define('PEAR_ERROR_PRINT', 2);
+define('PEAR_ERROR_TRIGGER', 4);
+define('PEAR_ERROR_DIE', 8);
+define('PEAR_ERROR_CALLBACK', 16);
+/**
+ * WARNING: obsolete
+ * @deprecated
+ */
+define('PEAR_ERROR_EXCEPTION', 32);
+/**#@-*/
+define('PEAR_ZE2', (function_exists('version_compare') &&
+ version_compare(zend_version(), "2-dev", "ge")));
+
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ define('OS_WINDOWS', true);
+ define('OS_UNIX', false);
+ define('PEAR_OS', 'Windows');
+} else {
+ define('OS_WINDOWS', false);
+ define('OS_UNIX', true);
+ define('PEAR_OS', 'Unix'); // blatant assumption
+}
+
+$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
+$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
+$GLOBALS['_PEAR_destructor_object_list'] = array();
+$GLOBALS['_PEAR_shutdown_funcs'] = array();
+$GLOBALS['_PEAR_error_handler_stack'] = array();
+
+@ini_set('track_errors', true);
+
+/**
+ * Base class for other PEAR classes. Provides rudimentary
+ * emulation of destructors.
+ *
+ * If you want a destructor in your class, inherit PEAR and make a
+ * destructor method called _yourclassname (same name as the
+ * constructor, but with a "_" prefix). Also, in your constructor you
+ * have to call the PEAR constructor: $this->PEAR();.
+ * The destructor method will be called without parameters. Note that
+ * at in some SAPI implementations (such as Apache), any output during
+ * the request shutdown (in which destructors are called) seems to be
+ * discarded. If you need to get any debug information from your
+ * destructor, use error_log(), syslog() or something similar.
+ *
+ * IMPORTANT! To use the emulated destructors you need to create the
+ * objects by reference: $obj =& new PEAR_child;
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/PEAR
+ * @see PEAR_Error
+ * @since Class available since PHP 4.0.2
+ * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
+ */
+class PEAR
+{
+ /**
+ * Whether to enable internal debug messages.
+ *
+ * @var bool
+ * @access private
+ */
+ var $_debug = false;
+
+ /**
+ * Default error mode for this object.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_mode = null;
+
+ /**
+ * Default error options used for this object when error mode
+ * is PEAR_ERROR_TRIGGER.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_options = null;
+
+ /**
+ * Default error handler (callback) for this object, if error mode is
+ * PEAR_ERROR_CALLBACK.
+ *
+ * @var string
+ * @access private
+ */
+ var $_default_error_handler = '';
+
+ /**
+ * Which class to use for error objects.
+ *
+ * @var string
+ * @access private
+ */
+ var $_error_class = 'PEAR_Error';
+
+ /**
+ * An array of expected errors.
+ *
+ * @var array
+ * @access private
+ */
+ var $_expected_errors = array();
+
+ /**
+ * Constructor. Registers this object in
+ * $_PEAR_destructor_object_list for destructor emulation if a
+ * destructor object exists.
+ *
+ * @param string $error_class (optional) which class to use for
+ * error objects, defaults to PEAR_Error.
+ * @access public
+ * @return void
+ */
+ function PEAR($error_class = null)
+ {
+ $classname = strtolower(get_class($this));
+ if ($this->_debug) {
+ print "PEAR constructor called, class=$classname\n";
+ }
+
+ if ($error_class !== null) {
+ $this->_error_class = $error_class;
+ }
+
+ while ($classname && strcasecmp($classname, "pear")) {
+ $destructor = "_$classname";
+ if (method_exists($this, $destructor)) {
+ global $_PEAR_destructor_object_list;
+ $_PEAR_destructor_object_list[] = &$this;
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+
+ /**
+ * Destructor (the emulated type of...). Does nothing right now,
+ * but is included for forward compatibility, so subclass
+ * destructors should always call it.
+ *
+ * See the note in the class description about output from
+ * destructors.
+ *
+ * @access public
+ * @return void
+ */
+ function _PEAR() {
+ if ($this->_debug) {
+ printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
+ }
+ }
+
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @access public
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+
+ return $properties[$class][$var];
+ }
+
+ /**
+ * Use this function to register a shutdown method for static
+ * classes.
+ *
+ * @access public
+ * @param mixed $func The function name (or array of class/method) to call
+ * @param mixed $args The arguments to pass to the function
+ * @return void
+ */
+ function registerShutdownFunc($func, $args = array())
+ {
+ // if we are called statically, there is a potential
+ // that no shutdown func is registered. Bug #6445
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
+ }
+
+ /**
+ * Tell whether a value is a PEAR error.
+ *
+ * @param mixed $data the value to test
+ * @param int $code if $data is an error object, return true
+ * only if $code is a string and
+ * $obj->getMessage() == $code or
+ * $code is an integer and $obj->getCode() == $code
+ * @access public
+ * @return bool true if parameter is an error
+ */
+ function isError($data, $code = null)
+ {
+ if (!is_object($data)) {
+ return false;
+ }
+ if (!is_a($data, 'PEAR_Error')) {
+ return false;
+ }
+
+ if (is_null($code)) {
+ return true;
+ } elseif (is_string($code)) {
+ return $data->getMessage() == $code;
+ }
+
+ return $data->getCode() == $code;
+ }
+
+ /**
+ * Sets how errors generated by this object should be handled.
+ * Can be invoked both in objects and statically. If called
+ * statically, setErrorHandling sets the default behaviour for all
+ * PEAR objects. If called in an object, setErrorHandling sets
+ * the default behaviour for that object.
+ *
+ * @param int $mode
+ * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options
+ * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
+ * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ *
+ * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
+ * to be the callback function or method. A callback
+ * function is a string with the name of the function, a
+ * callback method is an array of two elements: the element
+ * at index 0 is the object, and the element at index 1 is
+ * the name of the method to call in the object.
+ *
+ * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
+ * a printf format string used when printing the error
+ * message.
+ *
+ * @access public
+ * @return void
+ * @see PEAR_ERROR_RETURN
+ * @see PEAR_ERROR_PRINT
+ * @see PEAR_ERROR_TRIGGER
+ * @see PEAR_ERROR_DIE
+ * @see PEAR_ERROR_CALLBACK
+ * @see PEAR_ERROR_EXCEPTION
+ *
+ * @since PHP 4.0.5
+ */
+ function setErrorHandling($mode = null, $options = null)
+ {
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $setmode = &$this->_default_error_mode;
+ $setoptions = &$this->_default_error_options;
+ } else {
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ }
+
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ }
+
+ /**
+ * This method is used to tell which errors you expect to get.
+ * Expected errors are always returned with error mode
+ * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
+ * and this method pushes a new element onto it. The list of
+ * expected errors are in effect until they are popped off the
+ * stack with the popExpect() method.
+ *
+ * Note that this method can not be called statically
+ *
+ * @param mixed $code a single error code or an array of error codes to expect
+ *
+ * @return int the new depth of the "expected errors" stack
+ * @access public
+ */
+ function expectError($code = '*')
+ {
+ if (is_array($code)) {
+ array_push($this->_expected_errors, $code);
+ } else {
+ array_push($this->_expected_errors, array($code));
+ }
+ return count($this->_expected_errors);
+ }
+
+ /**
+ * This method pops one element off the expected error codes
+ * stack.
+ *
+ * @return array the list of error codes that were popped
+ */
+ function popExpect()
+ {
+ return array_pop($this->_expected_errors);
+ }
+
+ /**
+ * This method checks unsets an error code if available
+ *
+ * @param mixed error code
+ * @return bool true if the error code was unset, false otherwise
+ * @access private
+ * @since PHP 4.3.0
+ */
+ function _checkDelExpect($error_code)
+ {
+ $deleted = false;
+ foreach ($this->_expected_errors as $key => $error_array) {
+ if (in_array($error_code, $error_array)) {
+ unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
+ $deleted = true;
+ }
+
+ // clean up empty arrays
+ if (0 == count($this->_expected_errors[$key])) {
+ unset($this->_expected_errors[$key]);
+ }
+ }
+
+ return $deleted;
+ }
+
+ /**
+ * This method deletes all occurrences of the specified element from
+ * the expected error codes stack.
+ *
+ * @param mixed $error_code error code that should be deleted
+ * @return mixed list of error codes that were deleted or error
+ * @access public
+ * @since PHP 4.3.0
+ */
+ function delExpect($error_code)
+ {
+ $deleted = false;
+ if ((is_array($error_code) && (0 != count($error_code)))) {
+ // $error_code is a non-empty array here; we walk through it trying
+ // to unset all values
+ foreach ($error_code as $key => $error) {
+ $deleted = $this->_checkDelExpect($error) ? true : false;
+ }
+
+ return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ } elseif (!empty($error_code)) {
+ // $error_code comes alone, trying to unset it
+ if ($this->_checkDelExpect($error_code)) {
+ return true;
+ }
+
+ return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ }
+
+ // $error_code is empty
+ return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+ }
+
+ /**
+ * This method is a wrapper that returns an instance of the
+ * configured error class with this object's default error
+ * handling applied. If the $mode and $options parameters are not
+ * specified, the object's defaults are used.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
+ * specifies the PHP-internal error level (one of
+ * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ * If $mode is PEAR_ERROR_CALLBACK, this
+ * parameter specifies the callback function or
+ * method. In other error modes this parameter
+ * is ignored.
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @param string $error_class The returned error object will be
+ * instantiated from this class, if specified.
+ *
+ * @param bool $skipmsg If true, raiseError will only pass error codes,
+ * the error message parameter will be dropped.
+ *
+ * @access public
+ * @return object a PEAR error object
+ * @see PEAR::setErrorHandling
+ * @since PHP 4.0.5
+ */
+ function &raiseError($message = null,
+ $code = null,
+ $mode = null,
+ $options = null,
+ $userinfo = null,
+ $error_class = null,
+ $skipmsg = false)
+ {
+ // The error is yet a PEAR error object
+ if (is_object($message)) {
+ $code = $message->getCode();
+ $userinfo = $message->getUserInfo();
+ $error_class = $message->getType();
+ $message->error_message_prefix = '';
+ $message = $message->getMessage();
+
+ // Make sure right data gets passed.
+ $r = new ReflectionClass($error_class);
+ $c = $r->getConstructor();
+ $p = array_shift($c->getParameters());
+ $skipmsg = ($p->getName() != 'message');
+ }
+
+ if (
+ isset($this) &&
+ isset($this->_expected_errors) &&
+ count($this->_expected_errors) > 0 &&
+ count($exp = end($this->_expected_errors))
+ ) {
+ if ($exp[0] == "*" ||
+ (is_int(reset($exp)) && in_array($code, $exp)) ||
+ (is_string(reset($exp)) && in_array($message, $exp))
+ ) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ }
+
+ // No mode given, try global ones
+ if ($mode === null) {
+ // Class error handler
+ if (isset($this) && isset($this->_default_error_mode)) {
+ $mode = $this->_default_error_mode;
+ $options = $this->_default_error_options;
+ // Global error handler
+ } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
+ $mode = $GLOBALS['_PEAR_default_error_mode'];
+ $options = $GLOBALS['_PEAR_default_error_options'];
+ }
+ }
+
+ if ($error_class !== null) {
+ $ec = $error_class;
+ } elseif (isset($this) && isset($this->_error_class)) {
+ $ec = $this->_error_class;
+ } else {
+ $ec = 'PEAR_Error';
+ }
+
+ if (intval(PHP_VERSION) < 5) {
+ // little non-eval hack to fix bug #12147
+ include 'PEAR/FixPHP5PEARWarnings.php';
+ return $a;
+ }
+
+ if ($skipmsg) {
+ $a = new $ec($code, $mode, $options, $userinfo);
+ } else {
+ $a = new $ec($message, $code, $mode, $options, $userinfo);
+ }
+
+ return $a;
+ }
+
+ /**
+ * Simpler form of raiseError with fewer options. In most cases
+ * message, code and userinfo are enough.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @access public
+ * @return object a PEAR error object
+ * @see PEAR::raiseError
+ */
+ function &throwError($message = null, $code = null, $userinfo = null)
+ {
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $a = &$this->raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ function staticPushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ $stack[] = array($def_mode, $def_options);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $def_mode = $mode;
+ $def_options = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $def_mode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $def_options = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ function staticPopErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Push a new error handler on top of the error handler options stack. With this
+ * you can easily override the actual error handler for some code and restore
+ * it later with popErrorHandling.
+ *
+ * @param mixed $mode (same as setErrorHandling)
+ * @param mixed $options (same as setErrorHandling)
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::setErrorHandling
+ */
+ function pushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $def_mode = &$this->_default_error_mode;
+ $def_options = &$this->_default_error_options;
+ } else {
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ }
+ $stack[] = array($def_mode, $def_options);
+
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ /**
+ * Pop the last error handler used
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::pushErrorHandling
+ */
+ function popErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ return true;
+ }
+
+ /**
+ * OS independent PHP extension load. Remember to take care
+ * on the correct extension name for case sensitive OSes.
+ *
+ * @param string $ext The extension name
+ * @return bool Success or not on the dl() call
+ */
+ static function loadExtension($ext)
+ {
+ if (extension_loaded($ext)) {
+ return true;
+ }
+
+ // if either returns true dl() will produce a FATAL error, stop that
+ if (
+ function_exists('dl') === false ||
+ ini_get('enable_dl') != 1 ||
+ ini_get('safe_mode') == 1
+ ) {
+ return false;
+ }
+
+ if (OS_WINDOWS) {
+ $suffix = '.dll';
+ } elseif (PHP_OS == 'HP-UX') {
+ $suffix = '.sl';
+ } elseif (PHP_OS == 'AIX') {
+ $suffix = '.a';
+ } elseif (PHP_OS == 'OSX') {
+ $suffix = '.bundle';
+ } else {
+ $suffix = '.so';
+ }
+
+ return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+ }
+}
+
+if (PEAR_ZE2) {
+ /**
+ * This is only meant for PHP 5 to get rid of certain strict warning
+ * that doesn't get hidden since it's in the shutdown function
+ */
+ class PEAR5
+ {
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @access public
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ static function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+
+ return $properties[$class][$var];
+ }
+ }
+}
+
+function _PEAR_call_destructors()
+{
+ global $_PEAR_destructor_object_list;
+ if (is_array($_PEAR_destructor_object_list) &&
+ sizeof($_PEAR_destructor_object_list))
+ {
+ reset($_PEAR_destructor_object_list);
+ if (PEAR_ZE2) {
+ $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo');
+ } else {
+ $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
+ }
+
+ if ($destructLifoExists) {
+ $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
+ }
+
+ while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
+ $classname = get_class($objref);
+ while ($classname) {
+ $destructor = "_$classname";
+ if (method_exists($objref, $destructor)) {
+ $objref->$destructor();
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+ // Empty the object list to ensure that destructors are
+ // not called more than once.
+ $_PEAR_destructor_object_list = array();
+ }
+
+ // Now call the shutdown functions
+ if (
+ isset($GLOBALS['_PEAR_shutdown_funcs']) &&
+ is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
+ !empty($GLOBALS['_PEAR_shutdown_funcs'])
+ ) {
+ foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
+ call_user_func_array($value[0], $value[1]);
+ }
+ }
+}
+
+/**
+ * Standard PEAR error class for PHP 4
+ *
+ * This class is superseded by {@link PEAR_Exception} in PHP 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Gregory Beaver <cellog@php.net>
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/manual/en/core.pear.pear-error.php
+ * @see PEAR::raiseError(), PEAR::throwError()
+ * @since Class available since PHP 4.0.2
+ */
+class PEAR_Error
+{
+ var $error_message_prefix = '';
+ var $mode = PEAR_ERROR_RETURN;
+ var $level = E_USER_NOTICE;
+ var $code = -1;
+ var $message = '';
+ var $userinfo = '';
+ var $backtrace = null;
+
+ /**
+ * PEAR_Error constructor
+ *
+ * @param string $message message
+ *
+ * @param int $code (optional) error code
+ *
+ * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
+ * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
+ *
+ * @param mixed $options (optional) error level, _OR_ in the case of
+ * PEAR_ERROR_CALLBACK, the callback function or object/method
+ * tuple.
+ *
+ * @param string $userinfo (optional) additional user/debug info
+ *
+ * @access public
+ *
+ */
+ function PEAR_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ if ($mode === null) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ $this->message = $message;
+ $this->code = $code;
+ $this->mode = $mode;
+ $this->userinfo = $userinfo;
+
+ if (PEAR_ZE2) {
+ $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace');
+ } else {
+ $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
+ }
+
+ if (!$skiptrace) {
+ $this->backtrace = debug_backtrace();
+ if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
+ unset($this->backtrace[0]['object']);
+ }
+ }
+
+ if ($mode & PEAR_ERROR_CALLBACK) {
+ $this->level = E_USER_NOTICE;
+ $this->callback = $options;
+ } else {
+ if ($options === null) {
+ $options = E_USER_NOTICE;
+ }
+
+ $this->level = $options;
+ $this->callback = null;
+ }
+
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ } else {
+ $format = $options;
+ }
+
+ printf($format, $this->getMessage());
+ }
+
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ trigger_error($this->getMessage(), $this->level);
+ }
+
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $msg = $this->getMessage();
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ if (substr($msg, -1) != "\n") {
+ $msg .= "\n";
+ }
+ } else {
+ $format = $options;
+ }
+ die(sprintf($format, $msg));
+ }
+
+ if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
+ call_user_func($this->callback, $this);
+ }
+
+ if ($this->mode & PEAR_ERROR_EXCEPTION) {
+ trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
+ eval('$e = new Exception($this->message, $this->code);throw($e);');
+ }
+ }
+
+ /**
+ * Get the error mode from an error object.
+ *
+ * @return int error mode
+ * @access public
+ */
+ function getMode()
+ {
+ return $this->mode;
+ }
+
+ /**
+ * Get the callback function/method from an error object.
+ *
+ * @return mixed callback function or object/method array
+ * @access public
+ */
+ function getCallback()
+ {
+ return $this->callback;
+ }
+
+ /**
+ * Get the error message from an error object.
+ *
+ * @return string full error message
+ * @access public
+ */
+ function getMessage()
+ {
+ return ($this->error_message_prefix . $this->message);
+ }
+
+ /**
+ * Get error code from an error object
+ *
+ * @return int error code
+ * @access public
+ */
+ function getCode()
+ {
+ return $this->code;
+ }
+
+ /**
+ * Get the name of this error/exception.
+ *
+ * @return string error/exception name (type)
+ * @access public
+ */
+ function getType()
+ {
+ return get_class($this);
+ }
+
+ /**
+ * Get additional user-supplied information.
+ *
+ * @return string user-supplied information
+ * @access public
+ */
+ function getUserInfo()
+ {
+ return $this->userinfo;
+ }
+
+ /**
+ * Get additional debug information supplied by the application.
+ *
+ * @return string debug information
+ * @access public
+ */
+ function getDebugInfo()
+ {
+ return $this->getUserInfo();
+ }
+
+ /**
+ * Get the call backtrace from where the error was generated.
+ * Supported with PHP 4.3.0 or newer.
+ *
+ * @param int $frame (optional) what frame to fetch
+ * @return array Backtrace, or NULL if not available.
+ * @access public
+ */
+ function getBacktrace($frame = null)
+ {
+ if (defined('PEAR_IGNORE_BACKTRACE')) {
+ return null;
+ }
+ if ($frame === null) {
+ return $this->backtrace;
+ }
+ return $this->backtrace[$frame];
+ }
+
+ function addUserInfo($info)
+ {
+ if (empty($this->userinfo)) {
+ $this->userinfo = $info;
+ } else {
+ $this->userinfo .= " ** $info";
+ }
+ }
+
+ function __toString()
+ {
+ return $this->getMessage();
+ }
+
+ /**
+ * Make a string representation of this object.
+ *
+ * @return string a string with an object summary
+ * @access public
+ */
+ function toString()
+ {
+ $modes = array();
+ $levels = array(E_USER_NOTICE => 'notice',
+ E_USER_WARNING => 'warning',
+ E_USER_ERROR => 'error');
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_array($this->callback)) {
+ $callback = (is_object($this->callback[0]) ?
+ strtolower(get_class($this->callback[0])) :
+ $this->callback[0]) . '::' .
+ $this->callback[1];
+ } else {
+ $callback = $this->callback;
+ }
+ return sprintf('[%s: message="%s" code=%d mode=callback '.
+ 'callback=%s prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ $callback, $this->error_message_prefix,
+ $this->userinfo);
+ }
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ $modes[] = 'print';
+ }
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ $modes[] = 'trigger';
+ }
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $modes[] = 'die';
+ }
+ if ($this->mode & PEAR_ERROR_RETURN) {
+ $modes[] = 'return';
+ }
+ return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
+ 'prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ implode("|", $modes), $levels[$this->level],
+ $this->error_message_prefix,
+ $this->userinfo);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: php
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/src/etc/inc/auth.inc b/src/etc/inc/auth.inc
new file mode 100644
index 0000000..3c0acaa
--- /dev/null
+++ b/src/etc/inc/auth.inc
@@ -0,0 +1,1627 @@
+<?php
+/* $Id$ */
+/*
+ Copyright (C) 2010 Ermal Luçi
+ All rights reserved.
+
+ Copyright (C) 2007, 2008 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2005-2006 Bill Marquette <bill.marquette@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2006 Paul Taylor <paultaylor@winn-dixie.com>.
+ All rights reserved.
+
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /usr/sbin/pw /bin/cp
+ pfSense_MODULE: auth
+*/
+
+/*
+ * NOTE : Portions of the mschapv2 support was based on the BSD licensed CHAP.php
+ * file courtesy of Michael Retterklieber.
+ */
+if (!$do_not_include_config_gui_inc) {
+ require_once("config.gui.inc");
+}
+
+// Will be changed to false if security checks fail
+$security_passed = true;
+
+/* If this function doesn't exist, we're being called from Captive Portal or
+ another internal subsystem which does not include authgui.inc */
+if (function_exists("display_error_form") && !isset($config['system']['webgui']['nodnsrebindcheck'])) {
+ /* DNS ReBinding attack prevention. https://redmine.pfsense.org/issues/708 */
+ $found_host = false;
+
+ /* Either a IPv6 address with or without a alternate port */
+ if (strstr($_SERVER['HTTP_HOST'], "]")) {
+ $http_host_port = explode("]", $_SERVER['HTTP_HOST']);
+ /* v6 address has more parts, drop the last part */
+ if (count($http_host_port) > 1) {
+ array_pop($http_host_port);
+ $http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
+ } else {
+ $http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
+ }
+ } else {
+ $http_host = explode(":", $_SERVER['HTTP_HOST']);
+ $http_host = $http_host[0];
+ }
+ if (is_ipaddr($http_host) or $_SERVER['SERVER_ADDR'] == "127.0.0.1" or
+ strcasecmp($http_host, "localhost") == 0 or $_SERVER['SERVER_ADDR'] == "::1") {
+ $found_host = true;
+ }
+ if (strcasecmp($http_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 or
+ strcasecmp($http_host, $config['system']['hostname']) == 0) {
+ $found_host = true;
+ }
+
+ if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
+ foreach ($config['dyndnses']['dyndns'] as $dyndns) {
+ if (strcasecmp($dyndns['host'], $http_host) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
+ foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
+ if (strcasecmp($rfc2136['host'], $http_host) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
+ $althosts = explode(" ", $config['system']['webgui']['althostnames']);
+ foreach ($althosts as $ah) {
+ if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if ($found_host == false) {
+ if (!security_checks_disabled()) {
+ display_error_form("501", gettext("Potential DNS Rebind attack detected, see http://en.wikipedia.org/wiki/DNS_rebinding<br />Try accessing the router by IP address instead of by hostname."));
+ exit;
+ }
+ $security_passed = false;
+ }
+}
+
+// If the HTTP_REFERER is something other than ourselves then disallow.
+if (function_exists("display_error_form") && !isset($config['system']['webgui']['nohttpreferercheck'])) {
+ if ($_SERVER['HTTP_REFERER']) {
+ if (file_exists("{$g['tmp_path']}/setupwizard_lastreferrer")) {
+ if ($_SERVER['HTTP_REFERER'] == file_get_contents("{$g['tmp_path']}/setupwizard_lastreferrer")) {
+ unlink("{$g['tmp_path']}/setupwizard_lastreferrer");
+ header("Refresh: 1; url=index.php");
+ echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
+ echo "<html><head><title>" . gettext("Redirecting...") . "</title></head><body>" . gettext("Redirecting to the dashboard...") . "</body></html>";
+ exit;
+ }
+ }
+ $found_host = false;
+ $referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
+ $referrer_host = str_replace(array("[", "]"), "", $referrer_host);
+ if ($referrer_host) {
+ if (strcasecmp($referrer_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 ||
+ strcasecmp($referrer_host, $config['system']['hostname']) == 0) {
+ $found_host = true;
+ }
+
+ if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
+ $althosts = explode(" ", $config['system']['webgui']['althostnames']);
+ foreach ($althosts as $ah) {
+ if (strcasecmp($referrer_host, $ah) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
+ foreach ($config['dyndnses']['dyndns'] as $dyndns) {
+ if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
+ foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
+ if (strcasecmp($rfc2136['host'], $referrer_host) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ }
+
+ if (!$found_host) {
+ $interface_list_ips = get_configured_ip_addresses();
+ foreach ($interface_list_ips as $ilips) {
+ if (strcasecmp($referrer_host, $ilips) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ $interface_list_ipv6s = get_configured_ipv6_addresses();
+ foreach ($interface_list_ipv6s as $ilipv6s) {
+ if (strcasecmp($referrer_host, $ilipv6s) == 0) {
+ $found_host = true;
+ break;
+ }
+ }
+ if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
+ // allow SSH port forwarded connections and links from localhost
+ $found_host = true;
+ }
+ }
+ }
+ if ($found_host == false) {
+ if (!security_checks_disabled()) {
+ display_error_form("501", "An HTTP_REFERER was detected other than what is defined in System -> Advanced (" . htmlspecialchars($_SERVER['HTTP_REFERER']) . "). You can disable this check if needed in System -> Advanced -> Admin.");
+ exit;
+ }
+ $security_passed = false;
+ }
+ } else {
+ $security_passed = false;
+ }
+}
+
+if (function_exists("display_error_form") && $security_passed) {
+ /* Security checks passed, so it should be OK to turn them back on */
+ restore_security_checks();
+}
+unset($security_passed);
+
+$groupindex = index_groups();
+$userindex = index_users();
+
+function index_groups() {
+ global $g, $debug, $config, $groupindex;
+
+ $groupindex = array();
+
+ if (is_array($config['system']['group'])) {
+ $i = 0;
+ foreach ($config['system']['group'] as $groupent) {
+ $groupindex[$groupent['name']] = $i;
+ $i++;
+ }
+ }
+
+ return ($groupindex);
+}
+
+function index_users() {
+ global $g, $debug, $config;
+
+ if (is_array($config['system']['user'])) {
+ $i = 0;
+ foreach ($config['system']['user'] as $userent) {
+ $userindex[$userent['name']] = $i;
+ $i++;
+ }
+ }
+
+ return ($userindex);
+}
+
+function & getUserEntry($name) {
+ global $debug, $config, $userindex;
+ if (isset($userindex[$name])) {
+ return $config['system']['user'][$userindex[$name]];
+ }
+}
+
+function & getUserEntryByUID($uid) {
+ global $debug, $config;
+
+ if (is_array($config['system']['user'])) {
+ foreach ($config['system']['user'] as & $user) {
+ if ($user['uid'] == $uid) {
+ return $user;
+ }
+ }
+ }
+
+ return false;
+}
+
+function & getGroupEntry($name) {
+ global $debug, $config, $groupindex;
+ if (isset($groupindex[$name])) {
+ return $config['system']['group'][$groupindex[$name]];
+ }
+}
+
+function & getGroupEntryByGID($gid) {
+ global $debug, $config;
+
+ if (is_array($config['system']['group'])) {
+ foreach ($config['system']['group'] as & $group) {
+ if ($group['gid'] == $gid) {
+ return $group;
+ }
+ }
+ }
+
+ return false;
+}
+
+function get_user_privileges(& $user) {
+
+ $privs = $user['priv'];
+ if (!is_array($privs)) {
+ $privs = array();
+ }
+
+ $names = local_user_get_groups($user, true);
+
+ foreach ($names as $name) {
+ $group = getGroupEntry($name);
+ if (is_array($group['priv'])) {
+ $privs = array_merge($privs, $group['priv']);
+ }
+ }
+
+ return $privs;
+}
+
+function userHasPrivilege($userent, $privid = false) {
+
+ if (!$privid || !is_array($userent)) {
+ return false;
+ }
+
+ $privs = get_user_privileges($userent);
+
+ if (!is_array($privs)) {
+ return false;
+ }
+
+ if (!in_array($privid, $privs)) {
+ return false;
+ }
+
+ return true;
+}
+
+function local_backed($username, $passwd) {
+
+ $user = getUserEntry($username);
+ if (!$user) {
+ return false;
+ }
+
+ if (is_account_disabled($username) || is_account_expired($username)) {
+ return false;
+ }
+
+ if ($user['password']) {
+ if (crypt($passwd, $user['password']) == $user['password']) {
+ return true;
+ }
+ }
+
+ if ($user['md5-hash']) {
+ if (md5($passwd) == $user['md5-hash']) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function local_sync_accounts() {
+ global $debug, $config;
+ conf_mount_rw();
+
+ /* remove local users to avoid uid conflicts */
+ $fd = popen("/usr/sbin/pw usershow -a", "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = explode(":", fgets($fd));
+ if (((!strncmp($line[0], "_", 1)) || ($line[2] < 2000) || ($line[2] > 65000)) && ($line[0] != "admin")) {
+ continue;
+ }
+ /*
+ * If a crontab was created to user, pw userdel will be interactive and
+ * can cause issues. Just remove crontab before run it when necessary
+ */
+ unlink_if_exists("/var/cron/tabs/{$line[0]}");
+ $cmd = "/usr/sbin/pw userdel -n '{$line[0]}'";
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ mwexec($cmd);
+ }
+ pclose($fd);
+ }
+
+ /* remove local groups to avoid gid conflicts */
+ $gids = array();
+ $fd = popen("/usr/sbin/pw groupshow -a", "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = explode(":", fgets($fd));
+ if (!strncmp($line[0], "_", 1)) {
+ continue;
+ }
+ if ($line[2] < 2000) {
+ continue;
+ }
+ if ($line[2] > 65000) {
+ continue;
+ }
+ $cmd = "/usr/sbin/pw groupdel {$line[2]}";
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ mwexec($cmd);
+ }
+ pclose($fd);
+ }
+
+ /* make sure the all group exists */
+ $allgrp = getGroupEntryByGID(1998);
+ local_group_set($allgrp, true);
+
+ /* sync all local users */
+ if (is_array($config['system']['user'])) {
+ foreach ($config['system']['user'] as $user) {
+ local_user_set($user);
+ }
+ }
+
+ /* sync all local groups */
+ if (is_array($config['system']['group'])) {
+ foreach ($config['system']['group'] as $group) {
+ local_group_set($group);
+ }
+ }
+
+ conf_mount_ro();
+
+}
+
+function local_user_set(& $user) {
+ global $g, $debug;
+
+ if (empty($user['password'])) {
+ log_error("There is something wrong in your config because user {$user['name']} password is missing!");
+ return;
+ }
+
+ conf_mount_rw();
+
+ $home_base = "/home/";
+ $user_uid = $user['uid'];
+ $user_name = $user['name'];
+ $user_home = "{$home_base}{$user_name}";
+ $user_shell = "/etc/rc.initial";
+ $user_group = "nobody";
+
+ // Ensure $home_base exists and is writable
+ if (!is_dir($home_base)) {
+ mkdir($home_base, 0755);
+ }
+
+ $lock_account = false;
+ /* configure shell type */
+ /* Cases here should be ordered by most privileged to least privileged. */
+ if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
+ $user_shell = "/bin/tcsh";
+ } elseif (userHasPrivilege($user, "user-copy-files")) {
+ $user_shell = "/usr/local/bin/scponly";
+ } elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
+ $user_shell = "/usr/local/sbin/ssh_tunnel_shell";
+ } elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
+ $user_shell = "/sbin/nologin";
+ } else {
+ $user_shell = "/sbin/nologin";
+ $lock_account = true;
+ }
+
+ /* Lock out disabled or expired users, unless it's root/admin. */
+ if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
+ $user_shell = "/sbin/nologin";
+ $lock_account = true;
+ }
+
+ /* root user special handling */
+ if ($user_uid == 0) {
+ $cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ $fd = popen($cmd, "w");
+ fwrite($fd, $user['password']);
+ pclose($fd);
+ $user_group = "wheel";
+ $user_home = "/root";
+ $user_shell = "/etc/rc.initial";
+ }
+
+ /* read from pw db */
+ $fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
+ $pwread = fgets($fd);
+ pclose($fd);
+ $userattrs = explode(":", trim($pwread));
+
+ /* determine add or mod */
+ if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
+ $user_op = "useradd -m -k /etc/skel -o";
+ } else {
+ $user_op = "usermod";
+ }
+
+ $comment = str_replace(array(":", "!", "@"), " ", $user['descr']);
+ /* add or mod pw db */
+ $cmd = "/usr/sbin/pw {$user_op} -q -u {$user_uid} -n {$user_name}".
+ " -g {$user_group} -s {$user_shell} -d {$user_home}".
+ " -c ".escapeshellarg($comment)." -H 0 2>&1";
+
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ $fd = popen($cmd, "w");
+ fwrite($fd, $user['password']);
+ pclose($fd);
+
+ /* create user directory if required */
+ if (!is_dir($user_home)) {
+ mkdir($user_home, 0700);
+ }
+ @chown($user_home, $user_name);
+ @chgrp($user_home, $user_group);
+
+ /* write out ssh authorized key file */
+ if ($user['authorizedkeys']) {
+ if (!is_dir("{$user_home}/.ssh")) {
+ @mkdir("{$user_home}/.ssh", 0700);
+ @chown("{$user_home}/.ssh", $user_name);
+ }
+ $keys = base64_decode($user['authorizedkeys']);
+ @file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
+ @chown("{$user_home}/.ssh/authorized_keys", $user_name);
+ } else {
+ unlink_if_exists("{$user_home}/.ssh/authorized_keys");
+ }
+
+ $un = $lock_account ? "" : "un";
+ exec("/usr/sbin/pw {$un}lock {$user_name} -q");
+
+ conf_mount_ro();
+}
+
+function local_user_del($user) {
+ global $debug;
+
+ /* remove all memberships */
+ local_user_set_groups($user);
+
+ /* Don't remove /root */
+ if ($user['uid'] != 0) {
+ $rmhome = "-r";
+ }
+
+ /* read from pw db */
+ $fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
+ $pwread = fgets($fd);
+ pclose($fd);
+ $userattrs = explode(":", trim($pwread));
+
+ if ($userattrs[0] != $user['name']) {
+ log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
+ return;
+ }
+
+ /* delete from pw db */
+ $cmd = "/usr/sbin/pw userdel -n {$user['name']} {$rmhome}";
+
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ mwexec($cmd);
+
+ /* Delete user from groups needs a call to write_config() */
+ local_group_del_user($user);
+}
+
+function local_user_set_password(&$user, $password) {
+
+ $user['password'] = crypt($password);
+ $user['md5-hash'] = md5($password);
+
+ // Converts ascii to unicode.
+ $astr = (string) $password;
+ $ustr = '';
+ for ($i = 0; $i < strlen($astr); $i++) {
+ $a = ord($astr{$i}) << 8;
+ $ustr .= sprintf("%X", $a);
+ }
+
+}
+
+function local_user_get_groups($user, $all = false) {
+ global $debug, $config;
+
+ $groups = array();
+ if (!is_array($config['system']['group'])) {
+ return $groups;
+ }
+
+ foreach ($config['system']['group'] as $group) {
+ if ($all || (!$all && ($group['name'] != "all"))) {
+ if (is_array($group['member'])) {
+ if (in_array($user['uid'], $group['member'])) {
+ $groups[] = $group['name'];
+ }
+ }
+ }
+ }
+
+ if ($all) {
+ $groups[] = "all";
+ }
+
+ sort($groups);
+
+ return $groups;
+
+}
+
+function local_user_set_groups($user, $new_groups = NULL) {
+ global $debug, $config, $groupindex;
+
+ if (!is_array($config['system']['group'])) {
+ return;
+ }
+
+ $cur_groups = local_user_get_groups($user, true);
+ $mod_groups = array();
+
+ if (!is_array($new_groups)) {
+ $new_groups = array();
+ }
+
+ if (!is_array($cur_groups)) {
+ $cur_groups = array();
+ }
+
+ /* determine which memberships to add */
+ foreach ($new_groups as $groupname) {
+ if ($groupname == '' || in_array($groupname, $cur_groups)) {
+ continue;
+ }
+ $group = & $config['system']['group'][$groupindex[$groupname]];
+ $group['member'][] = $user['uid'];
+ $mod_groups[] = $group;
+ }
+ unset($group);
+
+ /* determine which memberships to remove */
+ foreach ($cur_groups as $groupname) {
+ if (in_array($groupname, $new_groups)) {
+ continue;
+ }
+ if (!isset($config['system']['group'][$groupindex[$groupname]])) {
+ continue;
+ }
+ $group = & $config['system']['group'][$groupindex[$groupname]];
+ if (is_array($group['member'])) {
+ $index = array_search($user['uid'], $group['member']);
+ array_splice($group['member'], $index, 1);
+ $mod_groups[] = $group;
+ }
+ }
+ unset($group);
+
+ /* sync all modified groups */
+ foreach ($mod_groups as $group) {
+ local_group_set($group);
+ }
+}
+
+function local_group_del_user($user) {
+ global $config;
+
+ if (!is_array($config['system']['group'])) {
+ return;
+ }
+
+ foreach ($config['system']['group'] as $group) {
+ if (is_array($group['member'])) {
+ foreach ($group['member'] as $idx => $uid) {
+ if ($user['uid'] == $uid) {
+ unset($config['system']['group']['member'][$idx]);
+ }
+ }
+ }
+ }
+}
+
+function local_group_set($group, $reset = false) {
+ global $debug;
+
+ $group_name = $group['name'];
+ $group_gid = $group['gid'];
+ $group_members = '';
+ if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
+ $group_members = implode(",", $group['member']);
+ }
+
+ if (empty($group_name)) {
+ return;
+ }
+
+ /* read from group db */
+ $fd = popen("/usr/sbin/pw groupshow {$group_name} 2>&1", "r");
+ $pwread = fgets($fd);
+ pclose($fd);
+
+ /* determine add or mod */
+ if (!strncmp($pwread, "pw:", 3)) {
+ $group_op = "groupadd";
+ } else {
+ $group_op = "groupmod";
+ }
+
+ /* add or mod group db */
+ $cmd = "/usr/sbin/pw {$group_op} {$group_name} -g {$group_gid} -M '{$group_members}' 2>&1";
+
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ mwexec($cmd);
+
+}
+
+function local_group_del($group) {
+ global $debug;
+
+ /* delete from group db */
+ $cmd = "/usr/sbin/pw groupdel {$group['name']}";
+
+ if ($debug) {
+ log_error(sprintf(gettext("Running: %s"), $cmd));
+ }
+ mwexec($cmd);
+}
+
+function ldap_test_connection($authcfg) {
+ global $debug, $config, $g;
+
+ if ($authcfg) {
+ if (strstr($authcfg['ldap_urltype'], "Standard")) {
+ $ldapproto = "ldap";
+ } else {
+ $ldapproto = "ldaps";
+ }
+ $ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
+ $ldapport = $authcfg['ldap_port'];
+ if (!empty($ldapport)) {
+ $ldapserver .= ":{$ldapport}";
+ }
+ $ldapbasedn = $authcfg['ldap_basedn'];
+ $ldapbindun = $authcfg['ldap_binddn'];
+ $ldapbindpw = $authcfg['ldap_bindpw'];
+ } else {
+ return false;
+ }
+
+ /* first check if there is even an LDAP server populated */
+ if (!$ldapserver) {
+ return false;
+ }
+
+ /* Setup CA environment if needed. */
+ ldap_setup_caenv($authcfg);
+
+ /* connect and see if server is up */
+ $error = false;
+ if (!($ldap = ldap_connect($ldapserver))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ log_error(sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname));
+ return false;
+ }
+
+ return true;
+}
+
+function ldap_setup_caenv($authcfg) {
+ global $g;
+ require_once("certs.inc");
+
+ unset($caref);
+ if (empty($authcfg['ldap_caref']) || !strstr($authcfg['ldap_urltype'], "SSL")) {
+ putenv('LDAPTLS_REQCERT=never');
+ return;
+ } else {
+ $caref = lookup_ca($authcfg['ldap_caref']);
+ if (!$caref) {
+ log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
+ /* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
+ putenv('LDAPTLS_REQCERT=hard');
+ return;
+ }
+ if (!is_dir("{$g['varrun_path']}/certs")) {
+ @mkdir("{$g['varrun_path']}/certs");
+ }
+ if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
+ @unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
+ }
+ file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", base64_decode($caref['crt']));
+ @chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
+ putenv('LDAPTLS_REQCERT=hard');
+ /* XXX: Probably even the hashed link should be created for this? */
+ putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
+ putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
+ }
+}
+
+function ldap_test_bind($authcfg) {
+ global $debug, $config, $g;
+
+ if ($authcfg) {
+ if (strstr($authcfg['ldap_urltype'], "Standard")) {
+ $ldapproto = "ldap";
+ } else {
+ $ldapproto = "ldaps";
+ }
+ $ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
+ $ldapport = $authcfg['ldap_port'];
+ if (!empty($ldapport)) {
+ $ldapserver .= ":{$ldapport}";
+ }
+ $ldapbasedn = $authcfg['ldap_basedn'];
+ $ldapbindun = $authcfg['ldap_binddn'];
+ $ldapbindpw = $authcfg['ldap_bindpw'];
+ $ldapver = $authcfg['ldap_protver'];
+ if (empty($ldapbndun) || empty($ldapbindpw)) {
+ $ldapanon = true;
+ } else {
+ $ldapanon = false;
+ }
+ } else {
+ return false;
+ }
+
+ /* first check if there is even an LDAP server populated */
+ if (!$ldapserver) {
+ return false;
+ }
+
+ /* Setup CA environment if needed. */
+ ldap_setup_caenv($authcfg);
+
+ /* connect and see if server is up */
+ $error = false;
+ if (!($ldap = ldap_connect($ldapserver))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ log_error(sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname));
+ return false;
+ }
+
+ ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
+ ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
+ ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
+
+ $ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
+ $ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
+ if ($ldapanon == true) {
+ if (!($res = @ldap_bind($ldap))) {
+ @ldap_close($ldap);
+ return false;
+ }
+ } else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
+ @ldap_close($ldap);
+ return false;
+ }
+
+ @ldap_unbind($ldap);
+
+ return true;
+}
+
+function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
+ global $debug, $config, $g;
+
+ if (!function_exists("ldap_connect")) {
+ return;
+ }
+
+ $ous = array();
+
+ if ($authcfg) {
+ if (strstr($authcfg['ldap_urltype'], "Standard")) {
+ $ldapproto = "ldap";
+ } else {
+ $ldapproto = "ldaps";
+ }
+ $ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
+ $ldapport = $authcfg['ldap_port'];
+ if (!empty($ldapport)) {
+ $ldapserver .= ":{$ldapport}";
+ }
+ $ldapbasedn = $authcfg['ldap_basedn'];
+ $ldapbindun = $authcfg['ldap_binddn'];
+ $ldapbindpw = $authcfg['ldap_bindpw'];
+ $ldapver = $authcfg['ldap_protver'];
+ if (empty($ldapbindun) || empty($ldapbindpw)) {
+ $ldapanon = true;
+ } else {
+ $ldapanon = false;
+ }
+ $ldapname = $authcfg['name'];
+ $ldapfallback = false;
+ $ldapscope = $authcfg['ldap_scope'];
+ } else {
+ return false;
+ }
+
+ /* first check if there is even an LDAP server populated */
+ if (!$ldapserver) {
+ log_error(gettext("ERROR! ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
+ return $ous;
+ }
+
+ /* Setup CA environment if needed. */
+ ldap_setup_caenv($authcfg);
+
+ /* connect and see if server is up */
+ $error = false;
+ if (!($ldap = ldap_connect($ldapserver))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ log_error(sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname));
+ return $ous;
+ }
+
+ $ldapfilter = "(|(ou=*)(cn=Users))";
+
+ ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
+ ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
+ ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
+
+ $ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
+ $ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
+ if ($ldapanon == true) {
+ if (!($res = @ldap_bind($ldap))) {
+ log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
+ @ldap_close($ldap);
+ return $ous;
+ }
+ } else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
+ log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
+ @ldap_close($ldap);
+ return $ous;
+ }
+
+ if ($ldapscope == "one") {
+ $ldapfunc = "ldap_list";
+ } else {
+ $ldapfunc = "ldap_search";
+ }
+
+ $search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
+ $info = @ldap_get_entries($ldap, $search);
+
+ if (is_array($info)) {
+ foreach ($info as $inf) {
+ if (!$show_complete_ou) {
+ $inf_split = explode(",", $inf['dn']);
+ $ou = $inf_split[0];
+ $ou = str_replace("OU=", "", $ou);
+ $ou = str_replace("CN=", "", $ou);
+ } else {
+ if ($inf['dn']) {
+ $ou = $inf['dn'];
+ }
+ }
+ if ($ou) {
+ $ous[] = $ou;
+ }
+ }
+ }
+
+ @ldap_unbind($ldap);
+
+ return $ous;
+}
+
+function ldap_get_groups($username, $authcfg) {
+ global $debug, $config;
+
+ if (!function_exists("ldap_connect")) {
+ return;
+ }
+
+ if (!$username) {
+ return false;
+ }
+
+ if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
+ $username_split = explode("@", $username);
+ $username = $username_split[0];
+ }
+
+ if (stristr($username, "\\")) {
+ $username_split = explode("\\", $username);
+ $username = $username_split[0];
+ }
+
+ //log_error("Getting LDAP groups for {$username}.");
+ if ($authcfg) {
+ if (strstr($authcfg['ldap_urltype'], "Standard")) {
+ $ldapproto = "ldap";
+ } else {
+ $ldapproto = "ldaps";
+ }
+ $ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
+ $ldapport = $authcfg['ldap_port'];
+ if (!empty($ldapport)) {
+ $ldapserver .= ":{$ldapport}";
+ }
+ $ldapbasedn = $authcfg['ldap_basedn'];
+ $ldapbindun = $authcfg['ldap_binddn'];
+ $ldapbindpw = $authcfg['ldap_bindpw'];
+ $ldapauthcont = $authcfg['ldap_authcn'];
+ $ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
+ $ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
+ $ldapfilter = "({$ldapnameattribute}={$username})";
+ $ldaptype = "";
+ $ldapver = $authcfg['ldap_protver'];
+ if (empty($ldapbindun) || empty($ldapbindpw)) {
+ $ldapanon = true;
+ } else {
+ $ldapanon = false;
+ }
+ $ldapname = $authcfg['name'];
+ $ldapfallback = false;
+ $ldapscope = $authcfg['ldap_scope'];
+ } else {
+ return false;
+ }
+
+ $ldapdn = $_SESSION['ldapdn'];
+
+ /*Convert attribute to lowercase. php ldap arrays put everything in lowercase */
+ $ldapgroupattribute = strtolower($ldapgroupattribute);
+ $memberof = array();
+
+ /* Setup CA environment if needed. */
+ ldap_setup_caenv($authcfg);
+
+ /* connect and see if server is up */
+ $error = false;
+ if (!($ldap = ldap_connect($ldapserver))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
+ return memberof;
+ }
+
+ ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
+ ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
+ ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
+
+ /* bind as user that has rights to read group attributes */
+ $ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
+ $ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
+ if ($ldapanon == true) {
+ if (!($res = @ldap_bind($ldap))) {
+ log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
+ @ldap_close($ldap);
+ return false;
+ }
+ } else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
+ log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
+ @ldap_close($ldap);
+ return memberof;
+ }
+
+ /* get groups from DN found */
+ /* use ldap_read instead of search so we don't have to do a bunch of extra work */
+ /* since we know the DN is in $_SESSION['ldapdn'] */
+ //$search = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
+ if ($ldapscope == "one") {
+ $ldapfunc = "ldap_list";
+ } else {
+ $ldapfunc = "ldap_search";
+ }
+
+ $search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
+ $info = @ldap_get_entries($ldap, $search);
+
+ $countem = $info["count"];
+
+ if (is_array($info[0][$ldapgroupattribute])) {
+ /* Iterate through the groups and throw them into an array */
+ foreach ($info[0][$ldapgroupattribute] as $member) {
+ if (stristr($member, "CN=") !== false) {
+ $membersplit = explode(",", $member);
+ $memberof[] = preg_replace("/CN=/i", "", $membersplit[0]);
+ }
+ }
+ }
+
+ /* Time to close LDAP connection */
+ @ldap_unbind($ldap);
+
+ $groups = print_r($memberof, true);
+
+ //log_error("Returning groups ".$groups." for user $username");
+
+ return $memberof;
+}
+
+function ldap_format_host($host) {
+ return is_ipaddrv6($host) ? "[$host]" : $host ;
+}
+
+function ldap_backed($username, $passwd, $authcfg) {
+ global $debug, $config;
+
+ if (!$username) {
+ return;
+ }
+
+ if (!function_exists("ldap_connect")) {
+ return;
+ }
+
+ if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
+ $username_split = explode("@", $username);
+ $username = $username_split[0];
+ }
+ if (stristr($username, "\\")) {
+ $username_split = explode("\\", $username);
+ $username = $username_split[0];
+ }
+
+ if ($authcfg) {
+ if (strstr($authcfg['ldap_urltype'], "Standard")) {
+ $ldapproto = "ldap";
+ } else {
+ $ldapproto = "ldaps";
+ }
+ $ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
+ $ldapport = $authcfg['ldap_port'];
+ if (!empty($ldapport)) {
+ $ldapserver .= ":{$ldapport}";
+ }
+ $ldapbasedn = $authcfg['ldap_basedn'];
+ $ldapbindun = $authcfg['ldap_binddn'];
+ $ldapbindpw = $authcfg['ldap_bindpw'];
+ if (empty($ldapbindun) || empty($ldapbindpw)) {
+ $ldapanon = true;
+ } else {
+ $ldapanon = false;
+ }
+ $ldapauthcont = $authcfg['ldap_authcn'];
+ $ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
+ $ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
+ $ldapextendedquery = $authcfg['ldap_extended_query'];
+ $ldapfilter = "";
+ if (!$ldapextendedqueryenabled) {
+ $ldapfilter = "({$ldapnameattribute}={$username})";
+ } else {
+ $ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
+ }
+ $ldaptype = "";
+ $ldapver = $authcfg['ldap_protver'];
+ $ldapname = $authcfg['name'];
+ $ldapscope = $authcfg['ldap_scope'];
+ } else {
+ return false;
+ }
+
+ /* first check if there is even an LDAP server populated */
+ if (!$ldapserver) {
+ if ($ldapfallback) {
+ log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined. Defaulting to local user database. Visit System -> User Manager."));
+ return local_backed($username, $passwd);
+ } else {
+ log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined."));
+ }
+
+ return false;
+ }
+
+ /* Setup CA environment if needed. */
+ ldap_setup_caenv($authcfg);
+
+ ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
+ ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
+ ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
+
+ /* Make sure we can connect to LDAP */
+ $error = false;
+ if (!($ldap = ldap_connect($ldapserver))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ log_error(sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname));
+ return false;
+ }
+
+ /* ok, its up. now, lets bind as the bind user so we can search it */
+ $error = false;
+ $ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
+ $ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
+ if ($ldapanon == true) {
+ if (!($res = @ldap_bind($ldap))) {
+ $error = true;
+ }
+ } else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
+ $error = true;
+ }
+
+ if ($error == true) {
+ @ldap_close($ldap);
+ log_error(sprintf(gettext("ERROR! Could not bind to server %s."), $ldapname));
+ return false;
+ }
+
+ /* Get LDAP Authcontainers and split em up. */
+ $ldac_splits = explode(";", $ldapauthcont);
+
+ /* setup the usercount so we think we haven't found anyone yet */
+ $usercount = 0;
+
+ /*****************************************************************/
+ /* We First find the user based on username and filter */
+ /* Then, once we find the first occurrence of that person */
+ /* We set session variables to point to the OU and DN of the */
+ /* Person. To later be used by ldap_get_groups. */
+ /* that way we don't have to search twice. */
+ /*****************************************************************/
+ if ($debug) {
+ log_auth(sprintf(gettext("Now Searching for %s in directory."), $username));
+ }
+ /* Iterate through the user containers for search */
+ foreach ($ldac_splits as $i => $ldac_split) {
+ $ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
+ $ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
+ $ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
+ /* Make sure we just use the first user we find */
+ if ($debug) {
+ log_auth(sprintf(gettext('Now Searching in server %1$s, container %2$s with filter %3$s.'), $ldapname, utf8_decode($ldac_split), utf8_decode($ldapfilter)));
+ }
+ if ($ldapscope == "one") {
+ $ldapfunc = "ldap_list";
+ } else {
+ $ldapfunc = "ldap_search";
+ }
+ /* Support legacy auth container specification. */
+ if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
+ $search = @$ldapfunc($ldap,$ldac_split,$ldapfilter);
+ } else {
+ $search = @$ldapfunc($ldap,$ldapsearchbasedn,$ldapfilter);
+ }
+ if (!$search) {
+ log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
+ continue;
+ }
+ $info = ldap_get_entries($ldap, $search);
+ $matches = $info['count'];
+ if ($matches == 1) {
+ $userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
+ $_SESSION['ldapou'] = $ldac_split[$i];
+ $_SESSION['ldapon'] = "true";
+ $usercount = 1;
+ break;
+ }
+ }
+
+ if ($usercount != 1) {
+ @ldap_unbind($ldap);
+ log_error(gettext("ERROR! Either LDAP search failed, or multiple users were found."));
+ return false;
+ }
+
+ /* Now lets bind as the user we found */
+ $passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
+ if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
+ log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
+ @ldap_unbind($ldap);
+ return false;
+ }
+
+ if ($debug) {
+ $userdn = isset($authcfg['ldap_utf8']) ? utf8_decode($userdn) : $userdn;
+ log_auth(sprintf(gettext('Logged in successfully as %1$s via LDAP server %2$s with DN = %3$s.'), $username, $ldapname, $userdn));
+ }
+
+ /* At this point we are bound to LDAP so the user was auth'd okay. Close connection. */
+ @ldap_unbind($ldap);
+
+ return true;
+}
+
+function radius_backed($username, $passwd, $authcfg, &$attributes = array()) {
+ global $debug, $config;
+ $ret = false;
+
+ require_once("radius.inc");
+
+ $rauth = new Auth_RADIUS_PAP($username, $passwd);
+ if ($authcfg) {
+ $radiusservers = array();
+ $radiusservers[0]['ipaddr'] = $authcfg['host'];
+ $radiusservers[0]['port'] = $authcfg['radius_auth_port'];
+ $radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
+ $radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
+ } else {
+ return false;
+ }
+
+ /* Add new servers to our instance */
+ foreach ($radiusservers as $radsrv) {
+ $timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
+ $rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
+ }
+
+ if (PEAR::isError($rauth->start())) {
+ $retvalue['auth_val'] = 1;
+ $retvalue['error'] = $rauth->getError();
+ if ($debug) {
+ printf(gettext("Radius start: %s<br />\n"), $retvalue['error']);
+ }
+ }
+
+ // XXX - billm - somewhere in here we need to handle securid challenge/response
+
+ /* Send request */
+ $result = $rauth->send();
+ if (PEAR::isError($result)) {
+ $retvalue['auth_val'] = 1;
+ $retvalue['error'] = $result->getMessage();
+ if ($debug) {
+ printf(gettext("Radius send failed: %s<br />\n"), $retvalue['error']);
+ }
+ } else if ($result === true) {
+ if ($rauth->getAttributes()) {
+ $attributes = $rauth->listAttributes();
+ }
+ $retvalue['auth_val'] = 2;
+ if ($debug) {
+ printf(gettext("Radius Auth succeeded")."<br />\n");
+ }
+ $ret = true;
+ } else {
+ $retvalue['auth_val'] = 3;
+ if ($debug) {
+ printf(gettext("Radius Auth rejected")."<br />\n");
+ }
+ }
+
+ // close OO RADIUS_AUTHENTICATION
+ $rauth->close();
+
+ return $ret;
+}
+
+/*
+ $attributes must contain a "class" key containing the groups and local
+ groups must exist to match.
+*/
+function radius_get_groups($attributes) {
+ $groups = array();
+ if (!empty($attributes) && is_array($attributes) && !empty($attributes['class'])) {
+ $groups = explode(";", $attributes['class']);
+ foreach ($groups as & $grp) {
+ $grp = trim($grp);
+ if (strtolower(substr($grp, 0, 3)) == "ou=") {
+ $grp = substr($grp, 3);
+ }
+ }
+ }
+ return $groups;
+}
+
+function get_user_expiration_date($username) {
+ $user = getUserEntry($username);
+ if ($user['expires']) {
+ return $user['expires'];
+ }
+}
+
+function is_account_expired($username) {
+ $expirydate = get_user_expiration_date($username);
+ if ($expirydate) {
+ if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function is_account_disabled($username) {
+ $user = getUserEntry($username);
+ if (isset($user['disabled'])) {
+ return true;
+ }
+
+ return false;
+}
+
+function auth_get_authserver($name) {
+ global $config;
+
+ if (is_array($config['system']['authserver'])) {
+ foreach ($config['system']['authserver'] as $authcfg) {
+ if ($authcfg['name'] == $name) {
+ return $authcfg;
+ }
+ }
+ }
+ if ($name == "Local Database") {
+ return array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
+ }
+}
+
+function auth_get_authserver_list() {
+ global $config;
+
+ $list = array();
+
+ if (is_array($config['system']['authserver'])) {
+ foreach ($config['system']['authserver'] as $authcfg) {
+ /* Add support for disabled entries? */
+ $list[$authcfg['name']] = $authcfg;
+ }
+ }
+
+ $list["Local Database"] = array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
+ return $list;
+}
+
+function getUserGroups($username, $authcfg, &$attributes = array()) {
+ global $config;
+
+ $allowed_groups = array();
+
+ switch ($authcfg['type']) {
+ case 'ldap':
+ $allowed_groups = @ldap_get_groups($username, $authcfg);
+ break;
+ case 'radius':
+ $allowed_groups = @radius_get_groups($attributes);
+ break;
+ default:
+ $user = getUserEntry($username);
+ $allowed_groups = @local_user_get_groups($user, true);
+ break;
+ }
+
+ $member_groups = array();
+ if (is_array($config['system']['group'])) {
+ foreach ($config['system']['group'] as $group) {
+ if (in_array($group['name'], $allowed_groups)) {
+ $member_groups[] = $group['name'];
+ }
+ }
+ }
+
+ return $member_groups;
+}
+
+function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
+
+ if (!$authcfg) {
+ return local_backed($username, $password);
+ }
+
+ $authenticated = false;
+ switch ($authcfg['type']) {
+ case 'ldap':
+ if (ldap_backed($username, $password, $authcfg)) {
+ $authenticated = true;
+ }
+ break;
+ case 'radius':
+ if (radius_backed($username, $password, $authcfg, $attributes)) {
+ $authenticated = true;
+ }
+ break;
+ default:
+ /* lookup user object by name */
+ if (local_backed($username, $password)) {
+ $authenticated = true;
+ }
+ break;
+ }
+
+ return $authenticated;
+}
+
+function session_auth() {
+ global $config, $_SESSION, $page;
+
+ // Handle HTTPS httponly and secure flags
+ $currentCookieParams = session_get_cookie_params();
+ session_set_cookie_params(
+ $currentCookieParams["lifetime"],
+ $currentCookieParams["path"],
+ NULL,
+ ($config['system']['webgui']['protocol'] == "https"),
+ true
+ );
+
+ if (!session_id()) {
+ session_start();
+ }
+
+ // Detect protocol change
+ if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
+ return false;
+ }
+
+ /* Validate incoming login request */
+ $attributes = array();
+ if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) {
+ $authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
+ if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes) ||
+ authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
+ // Generate a new id to avoid session fixation
+ session_regenerate_id();
+ $_SESSION['Logged_In'] = "True";
+ $_SESSION['Username'] = $_POST['usernamefld'];
+ $_SESSION['user_radius_attributes'] = $attributes;
+ $_SESSION['last_access'] = time();
+ $_SESSION['protocol'] = $config['system']['webgui']['protocol'];
+ if (!isset($config['system']['webgui']['quietlogin'])) {
+ log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], $_SERVER['REMOTE_ADDR']));
+ }
+ if (isset($_POST['postafterlogin'])) {
+ return true;
+ } else {
+ if (empty($page)) {
+ $page = "/";
+ }
+ header("Location: {$page}");
+ }
+ exit;
+ } else {
+ /* give the user an error message */
+ $_SESSION['Login_Error'] = "Username or Password incorrect";
+ log_auth("webConfigurator authentication error for '{$_POST['usernamefld']}' from {$_SERVER['REMOTE_ADDR']}");
+ if (isAjax()) {
+ echo "showajaxmessage('{$_SESSION['Login_Error']}');";
+ return;
+ }
+ }
+ }
+
+ /* Show login page if they aren't logged in */
+ if (empty($_SESSION['Logged_In'])) {
+ return false;
+ }
+
+ /* If session timeout isn't set, we don't mark sessions stale */
+ if (!isset($config['system']['webgui']['session_timeout'])) {
+ /* Default to 4 hour timeout if one is not set */
+ if ($_SESSION['last_access'] < (time() - 14400)) {
+ $_GET['logout'] = true;
+ $_SESSION['Logout'] = true;
+ } else {
+ $_SESSION['last_access'] = time();
+ }
+ } else if (intval($config['system']['webgui']['session_timeout']) == 0) {
+ /* only update if it wasn't ajax */
+ if (!isAjax()) {
+ $_SESSION['last_access'] = time();
+ }
+ } else {
+ /* Check for stale session */
+ if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
+ $_GET['logout'] = true;
+ $_SESSION['Logout'] = true;
+ } else {
+ /* only update if it wasn't ajax */
+ if (!isAjax()) {
+ $_SESSION['last_access'] = time();
+ }
+ }
+ }
+
+ /* user hit the logout button */
+ if (isset($_GET['logout'])) {
+
+ if ($_SESSION['Logout']) {
+ log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
+ } else {
+ log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
+ }
+
+ /* wipe out $_SESSION */
+ $_SESSION = array();
+
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time()-42000, '/');
+ }
+
+ /* and destroy it */
+ session_destroy();
+
+ $scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
+ $scriptElms = count($scriptName);
+ $scriptName = $scriptName[$scriptElms-1];
+
+ if (isAjax()) {
+ return false;
+ }
+
+ /* redirect to page the user is on, it'll prompt them to login again */
+ header("Location: {$scriptName}");
+
+ return false;
+ }
+
+ /*
+ * this is for debugging purpose if you do not want to use Ajax
+ * to submit a HTML form. It basically disables the observation
+ * of the submit event and hence does not trigger Ajax.
+ */
+ if ($_GET['disable_ajax']) {
+ $_SESSION['NO_AJAX'] = "True";
+ }
+
+ /*
+ * Same to re-enable Ajax.
+ */
+ if ($_GET['enable_ajax']) {
+ unset($_SESSION['NO_AJAX']);
+ }
+
+ return true;
+}
+
+?>
diff --git a/src/etc/inc/authgui.inc b/src/etc/inc/authgui.inc
new file mode 100644
index 0000000..07cf9a9
--- /dev/null
+++ b/src/etc/inc/authgui.inc
@@ -0,0 +1,335 @@
+<?php
+/* $Id$ */
+/*
+ Copyright (C) 2007, 2008 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2005-2006 Bill Marquette <bill.marquette@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2006 Paul Taylor <paultaylor@winn-dixie.com>.
+ All rights reserved.
+
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_MODULE: authgui
+*/
+
+include_once("auth.inc");
+include_once("priv.inc");
+if (!function_exists('platform_booting')) {
+ require_once('globals.inc');
+}
+
+/* Authenticate user - exit if failed */
+if (!session_auth()) {
+ display_login_form();
+ exit;
+}
+
+/*
+ * Once here, the user has authenticated with the web server.
+ * We give them access only to the appropriate pages based on
+ * the user or group privileges.
+ */
+$allowedpages = getAllowedPages($_SESSION['Username'], $_SESSION['user_radius_attributes']);
+
+/*
+ * redirect to first allowed page if requesting a wrong url
+ */
+if (!isAllowedPage($_SERVER['REQUEST_URI'])) {
+ if (count($allowedpages) > 0) {
+ $page = str_replace('*', '', $allowedpages[0]);
+ $_SESSION['Post_Login'] = true;
+ require_once("functions.inc");
+ pfSenseHeader("/{$page}");
+
+ $username = empty($_SESSION["Username"]) ? "(system)" : $_SESSION['Username'];
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
+ $username .= '@' . $_SERVER['REMOTE_ADDR'];
+ }
+ log_error("{$username} attempted to access {$_SERVER['SCRIPT_NAME']} but does not have access to that page. Redirecting to {$page}.");
+
+ exit;
+ } else {
+ display_error_form("201", gettext("No page assigned to this user! Click here to logout."));
+ exit;
+ }
+} else {
+ $_SESSION['Post_Login'] = true;
+}
+
+/*
+ * redirect browsers post-login to avoid pages
+ * taking action in response to a POST request
+ */
+if (!$_SESSION['Post_Login']) {
+ $_SESSION['Post_Login'] = true;
+ require_once("functions.inc");
+ pfSenseHeader($_SERVER['REQUEST_URI']);
+ exit;
+}
+
+/*
+ * Close session data to allow other scripts from same host to come in.
+ * A session can be reactivated from calling session_start again
+ */
+session_commit();
+
+/*
+ * determine if the user is allowed access to the requested page
+ */
+function display_error_form($http_code, $desc) {
+ global $config, $g;
+ $g['theme'] = get_current_theme();
+ if (isAjax()) {
+ printf(gettext('Error: %1$s Description: %2$s'), $http_code, $desc);
+ return;
+ }
+
+?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script type="text/javascript" src="/javascript/jquery-1.11.1.min.js"></script>
+ <script type="text/javascript" src="/javascript/jquery-migrate-1.2.1.min.js"></script>
+ <title><?=$http_code?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="shortcut icon" href="/themes/<?= $g['theme'] ?>/images/icons/favicon.ico" />
+ <?php if (file_exists("{$g['www_path']}/themes/{$g['theme']}/login.css")): ?>
+ <link rel="stylesheet" type="text/css" href="/themes/<?= $g['theme'] ?>/login.css" media="all" />
+ <?php else: ?>
+ <link rel="stylesheet" type="text/css" href="/themes/<?= $g['theme'] ?>/all.css" media="all" />
+ <?php endif; ?>
+ <script type="text/javascript">
+ //<![CDATA[
+ function page_load() {}
+ function clearError() {
+ if ($('#inputerrors')) {
+ $('#inputerrors').html('');
+ }
+ }
+ <?php
+ require("headjs.php");
+ echo getHeadJS();
+ ?>
+ //]]>
+ </script>
+ <script type="text/javascript" src="/themes/<?= $g['theme'] ?>/javascript/niftyjsCode.js"></script>
+ </head>
+ <body onload="page_load();">
+ <div id="errordesc">
+ <h1>&nbsp</h1>
+ <a href="/index.php?logout">
+ <p id="errortext" style="vertical-align: middle; text-align: center;">
+ <span style="color: #000000; font-weight: bold;">
+ <?=$desc;?>
+ </span>
+ </p>
+ </div>
+ </body>
+</html>
+
+<?php
+
+} // end function
+
+
+function display_login_form() {
+ require_once("globals.inc");
+ global $config, $g;
+ $g['theme'] = get_current_theme();
+
+ unset($input_errors);
+
+ if (isAjax()) {
+ if (isset($_POST['login'])) {
+ if ($_SESSION['Logged_In'] <> "True") {
+ isset($_SESSION['Login_Error']) ? $login_error = $_SESSION['Login_Error'] : $login_error = gettext("unknown reason");
+ printf("showajaxmessage('" . gettext("Invalid login (%s).") . "')", $login_error);
+ }
+ if (file_exists("{$g['tmp_path']}/webconfigurator.lock")) {
+ // TODO: add the IP from the user who did lock the device
+ $whom = file_get_contents("{$g['tmp_path']}/webconfigurator.lock");
+ printf("showajaxmessage('" . gettext("This device is currently being maintained by: %s.") . "');", $whom);
+ }
+ }
+ exit;
+ }
+
+/* Check against locally configured IP addresses, which will catch when someone
+ port forwards WebGUI access from WAN to an internal IP on the router. */
+global $FilterIflist, $nifty_background;
+$local_ip = false;
+if (strpos($_SERVER['HTTP_HOST'], ":") === FALSE) {
+ $http_host_port = explode(":", $_SERVER['HTTP_HOST']);
+ $http_host = $http_host_port[0];
+} else {
+ $http_host = $_SERVER['HTTP_HOST'];
+}
+if (empty($FilterIflist)) {
+ require_once('filter.inc');
+ require_once('shaper.inc');
+ filter_generate_optcfg_array();
+}
+foreach ($FilterIflist as $iflist) {
+ if ($iflist['ip'] == $http_host) {
+ $local_ip = true;
+ } else if ($iflist['ipv6'] == $http_host) {
+ $local_ip = true;
+ } else if (is_array($iflist['vips'])) {
+ foreach ($iflist['vips'] as $vip) {
+ if ($vip['ip'] == $http_host) {
+ $local_ip = true;
+ break;
+ }
+ }
+ unset($vip);
+ }
+ if ($local_ip == true) {
+ break;
+ }
+}
+unset($FilterIflist);
+unset($iflist);
+
+if ($local_ip == false) {
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
+ if (is_ipaddrv4($http_host) && !empty($ovpns['tunnel_network']) && ip_in_subnet($http_host, $ovpns['tunnel_network'])) {
+ $local_ip = true;
+ } else if (is_ipaddrv6($http_host) && !empty($ovpns['tunnel_networkv6']) && ip_in_subnet($http_host, $ovpns['tunnel_networkv6'])) {
+ $local_ip = true;
+ }
+ if ($local_ip == true) {
+ break;
+ }
+ }
+ }
+}
+
+?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script type="text/javascript" src="/javascript/jquery-1.11.1.min.js"></script>
+ <script type="text/javascript" src="/javascript/jquery-migrate-1.2.1.min.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(document).ready(function() { jQuery('#usernamefld').focus(); });
+ //]]>
+ </script>
+
+ <title><?=gettext("Login"); ?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="shortcut icon" href="/themes/<?= $g['theme'] ?>/images/icons/favicon.ico" />
+ <?php if (file_exists("{$g['www_path']}/themes/{$g['theme']}/login.css")): ?>
+ <link rel="stylesheet" type="text/css" href="/themes/<?= $g['theme'] ?>/login.css" media="all" />
+ <?php else: ?>
+ <link rel="stylesheet" type="text/css" href="/themes/<?= $g['theme'] ?>/all.css" media="all" />
+ <?php endif; ?>
+ <script type="text/javascript">
+ //<![CDATA[
+ function page_load() {}
+ function clearError() {
+ if ($('#inputerrors')) {
+ $('#inputerrors').html('');
+ }
+ }
+ <?php
+ require("headjs.php");
+ echo getHeadJS();
+ ?>
+ //]]>
+ </script>
+ <script type="text/javascript" src="/themes/<?= $g['theme'] ?>/javascript/niftyjsCode.js"></script>
+ </head>
+ <body onload="page_load()">
+ <div id="login">
+ <?php
+ if (is_ipaddr($http_host) && !$local_ip && !isset($config['system']['webgui']['nohttpreferercheck'])) {
+ $nifty_background = "#999";
+ print_info_box(gettext("You are accessing this router by an IP address not configured locally, which may be forwarded by NAT or other means. <br /><br />If you did not setup this forwarding, you may be the target of a man-in-the-middle attack."));
+ }
+ $loginautocomplete = isset($config['system']['webgui']['loginautocomplete']) ? '' : 'autocomplete="off"';
+ ?>
+ <form id="iform" name="iform" method="post" <?= $loginautocomplete ?> action="<?=$_SERVER['SCRIPT_NAME'];?>">
+ <h1>&nbsp;</h1>
+ <div id="inputerrors"><?=$_SESSION['Login_Error'];?></div>
+ <p>
+ <span style="text-align:left">
+ <?=gettext("Username:"); ?><br />
+ <input onclick="clearError();" onchange="clearError();" id="usernamefld" type="text" name="usernamefld" class="formfld user" tabindex="1" />
+ </span>
+ </p>
+ <p>
+ <br />
+ <span style="text-align:left">
+ <?=gettext("Password:"); ?> <br />
+ <input onclick="clearError();" onchange="clearError();" id="passwordfld" type="password" name="passwordfld" class="formfld pwd" tabindex="2" />
+ </span>
+ </p>
+ <p>
+ <br />
+ <span style="text-align:center; font-weight: normal ; font-style: italic">
+ <?=gettext("Enter username and password to login."); ?>
+ </span>
+
+ <span style="text-align:center; font-weight: normal ; font-style: italic; color: #ff0000; display:none" id="no_cookies">
+ <br /><br />
+ <?= gettext("Your browser must support cookies to login."); ?>
+ </span>
+ </p>
+ <p>
+ <span style="text-align:center">
+ <input type="submit" name="login" class="formbtn" value="<?=gettext("Login"); ?>" tabindex="3" />
+ </span>
+ </p>
+ </form>
+ </div>
+ <script type="text/javascript">
+ //<![CDATA[
+ document.cookie=
+ "cookie_test=1" +
+ "<?php echo $config['system']['webgui']['protocol'] == 'https' ? '; secure' : '';?>";
+
+ if (document.cookie.indexOf("cookie_test") == -1) {
+ document.getElementById("no_cookies").style.display="";
+ }
+
+ // Delete it
+ document.cookie = "cookie_test=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
+ //]]>
+ </script>
+ </body>
+</html>
+<?php
+} // end function
+
+?>
diff --git a/src/etc/inc/basic_sasl_client.inc b/src/etc/inc/basic_sasl_client.inc
new file mode 100644
index 0000000..c817664
--- /dev/null
+++ b/src/etc/inc/basic_sasl_client.inc
@@ -0,0 +1,63 @@
+<?php
+/*
+ * basic_sasl_client.php
+ *
+ * @(#) $Id: basic_sasl_client.php,v 1.1 2004/11/17 08:01:23 mlemos Exp $
+ *
+ */
+
+define("SASL_BASIC_STATE_START", 0);
+define("SASL_BASIC_STATE_DONE", 1);
+
+class basic_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_BASIC_STATE_START;
+
+ Function Initialize(&$client)
+ {
+ return(1);
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if ($this->state!=SASL_BASIC_STATE_START)
+ {
+ $client->error="Basic authentication state is not at the start";
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ "user"=>"",
+ "password"=>""
+ );
+ $defaults=array(
+ );
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if ($status==SASL_CONTINUE)
+ {
+ $message=$this->credentials["user"].":".$this->credentials["password"];
+ $this->state=SASL_BASIC_STATE_DONE;
+ }
+ else
+ {
+ Unset($message);
+ }
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch ($this->state)
+ {
+ case SASL_BASIC_STATE_DONE:
+ $client->error="Basic authentication was finished without success";
+ return(SASL_FAIL);
+ default:
+ $client->error="invalid Basic authentication step state";
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc
new file mode 100644
index 0000000..bd294e4
--- /dev/null
+++ b/src/etc/inc/captiveportal.inc
@@ -0,0 +1,2409 @@
+<?php
+/*
+ captiveportal.inc
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004-2011 Scott Ullrich <sullrich@gmail.com>
+ Copyright (C) 2009-2012 Ermal Luçi <eri@pfsense.org>
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ This version of captiveportal.inc has been modified by Rob Parker
+ <rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
+ via returned RADIUS attributes. This page has been modified to delete any
+ added rules which may have been created by other per-user code (index.php, etc).
+ These changes are (c) 2004 Keycom PLC.
+
+ pfSense_BUILDER_BINARIES: /sbin/ipfw /sbin/route
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/lighttpd /usr/local/bin/minicron /sbin/pfctl
+ pfSense_BUILDER_BINARIES: /bin/hostname /bin/cp
+ pfSense_MODULE: captiveportal
+*/
+
+/* include all configuration functions */
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("radius.inc");
+require_once("voucher.inc");
+
+function get_default_captive_portal_html() {
+ global $config, $g, $cpzone;
+
+ $htmltext = <<<EOD
+<html>
+<body>
+<form method="post" action="\$PORTAL_ACTION\$">
+ <input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
+ <input name="zone" type="hidden" value="\$PORTAL_ZONE\$">
+ <center>
+ <table cellpadding="6" cellspacing="0" width="550" height="380" style="border:1px solid #000000">
+ <tr height="10" bgcolor="#990000">
+ <td style="border-bottom:1px solid #000000">
+ <font color='white'>
+ <b>
+ {$g['product_name']} captive portal
+ </b>
+ </font>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div id="mainlevel">
+ <center>
+ <table width="100%" border="0" cellpadding="5" cellspacing="0">
+ <tr>
+ <td>
+ <center>
+ <div id="mainarea">
+ <center>
+ <table width="100%" border="0" cellpadding="5" cellspacing="5">
+ <tr>
+ <td>
+ <div id="maindivarea">
+ <center>
+ <div id='statusbox'>
+ <font color='red' face='arial' size='+1'>
+ <b>
+ \$PORTAL_MESSAGE\$
+ </b>
+ </font>
+ </div>
+ <br />
+ <div id='loginbox'>
+ <table>
+ <tr><td colspan="2"><center>Welcome to the {$g['product_name']} Captive Portal!</td></tr>
+ <tr><td>&nbsp;</td></tr>
+ <tr><td align="right">Username:</td><td><input name="auth_user" type="text" style="border: 1px dashed;"></td></tr>
+ <tr><td align="right">Password:</td><td><input name="auth_pass" type="password" style="border: 1px dashed;"></td></tr>
+ <tr><td>&nbsp;</td></tr>
+
+EOD;
+
+ if (isset($config['voucher'][$cpzone]['enable'])) {
+ $htmltext .= <<<EOD
+ <tr>
+ <td align="right">Enter Voucher Code: </td>
+ <td><input name="auth_voucher" type="text" style="border:1px dashed;" size="22"></td>
+ </tr>
+
+EOD;
+ }
+
+ $htmltext .= <<<EOD
+ <tr>
+ <td colspan="2"><center><input name="accept" type="submit" value="Continue"></center></td>
+ </tr>
+ </table>
+ </div>
+ </center>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </center>
+ </div>
+ </center>
+ </td>
+ </tr>
+ </table>
+ </center>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </center>
+</form>
+</body>
+</html>
+
+EOD;
+
+ return $htmltext;
+}
+
+function captiveportal_load_modules() {
+ global $config;
+
+ mute_kernel_msgs();
+ if (!is_module_loaded("ipfw.ko")) {
+ mwexec("/sbin/kldload ipfw");
+ /* make sure ipfw is not on pfil hooks */
+ set_sysctl(array(
+ "net.inet.ip.pfil.inbound" => "pf", "net.inet6.ip6.pfil.inbound" => "pf",
+ "net.inet.ip.pfil.outbound" => "pf", "net.inet6.ip6.pfil.outbound" => "pf")
+ );
+ }
+ /* Activate layer2 filtering */
+ set_sysctl(array("net.link.ether.ipfw" => "1", "net.inet.ip.fw.one_pass" => "1"));
+
+ /* Always load dummynet now that even allowed ip and mac passthrough use it. */
+ if (!is_module_loaded("dummynet.ko")) {
+ mwexec("/sbin/kldload dummynet");
+ set_sysctl(array("net.inet.ip.dummynet.io_fast" => "1", "net.inet.ip.dummynet.hash_size" => "256"));
+ }
+ unmute_kernel_msgs();
+}
+
+function captiveportal_configure() {
+ global $config, $cpzone, $cpzoneid;
+
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpkey => $cp) {
+ $cpzone = $cpkey;
+ $cpzoneid = $cp['zoneid'];
+ captiveportal_configure_zone($cp);
+ }
+ }
+}
+
+function captiveportal_configure_zone($cpcfg) {
+ global $config, $g, $cpzone, $cpzoneid;
+
+ $captiveportallck = lock("captiveportal{$cpzone}", LOCK_EX);
+
+ if (isset($cpcfg['enable'])) {
+
+ if (platform_booting()) {
+ echo "Starting captive portal({$cpcfg['zone']})... ";
+
+ /* remove old information */
+ unlink_if_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db");
+ } else {
+ captiveportal_syslog("Reconfiguring captive portal({$cpcfg['zone']}).");
+ }
+
+ /* init ipfw rules */
+ captiveportal_init_rules(true);
+
+ /* kill any running minicron */
+ killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
+
+ /* initialize minicron interval value */
+ $croninterval = $cpcfg['croninterval'] ? $cpcfg['croninterval'] : 60;
+
+ /* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
+ if ((!is_numeric($croninterval)) || ($croninterval < 10)) {
+ $croninterval = 60;
+ }
+
+ /* write portal page */
+ if (is_array($cpcfg['page']) && $cpcfg['page']['htmltext']) {
+ $htmltext = base64_decode($cpcfg['page']['htmltext']);
+ } else {
+ /* example/template page */
+ $htmltext = get_default_captive_portal_html();
+ }
+
+ $fd = @fopen("{$g['varetc_path']}/captiveportal_{$cpzone}.html", "w");
+ if ($fd) {
+ // Special case handling. Convert so that we can pass this page
+ // through the PHP interpreter later without clobbering the vars.
+ $htmltext = str_replace("\$PORTAL_ZONE\$", "#PORTAL_ZONE#", $htmltext);
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $htmltext);
+ $htmltext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $htmltext);
+ $htmltext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $htmltext);
+ $htmltext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $htmltext);
+ $htmltext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $htmltext);
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $htmltext);
+ if ($cpcfg['preauthurl']) {
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $htmltext);
+ $htmltext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $htmltext);
+ }
+ fwrite($fd, $htmltext);
+ fclose($fd);
+ }
+ unset($htmltext);
+
+ /* write error page */
+ if (is_array($cpcfg['page']) && $cpcfg['page']['errtext']) {
+ $errtext = base64_decode($cpcfg['page']['errtext']);
+ } else {
+ /* example page */
+ $errtext = get_default_captive_portal_html();
+ }
+
+ $fd = @fopen("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html", "w");
+ if ($fd) {
+ // Special case handling. Convert so that we can pass this page
+ // through the PHP interpreter later without clobbering the vars.
+ $errtext = str_replace("\$PORTAL_ZONE\$", "#PORTAL_ZONE#", $errtext);
+ $errtext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $errtext);
+ $errtext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $errtext);
+ $errtext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $errtext);
+ $errtext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $errtext);
+ $errtext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $errtext);
+ $errtext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $errtext);
+ if ($cpcfg['preauthurl']) {
+ $errtext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $errtext);
+ $errtext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $errtext);
+ }
+ fwrite($fd, $errtext);
+ fclose($fd);
+ }
+ unset($errtext);
+
+ /* write logout page */
+ if (is_array($cpcfg['page']) && $cpcfg['page']['logouttext']) {
+ $logouttext = base64_decode($cpcfg['page']['logouttext']);
+ } else {
+ /* example page */
+ $logouttext = <<<EOD
+<html>
+<head><title>Redirecting...</title></head>
+<body>
+<span style="font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
+<b>Redirecting to <a href="<?=\$my_redirurl;?>"><?=\$my_redirurl;?></a>...</b>
+</span>
+<script type="text/javascript">
+//<![CDATA[
+LogoutWin = window.open('', 'Logout', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=256,height=64');
+if (LogoutWin) {
+ LogoutWin.document.write('<html>');
+ LogoutWin.document.write('<head><title>Logout</title></head>') ;
+ LogoutWin.document.write('<body bgcolor="#435370">');
+ LogoutWin.document.write('<div align="center" style="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">') ;
+ LogoutWin.document.write('<b>Click the button below to disconnect</b><p />');
+ LogoutWin.document.write('<form method="POST" action="<?=\$logouturl;?>">');
+ LogoutWin.document.write('<input name="logout_id" type="hidden" value="<?=\$sessionid;?>" />');
+ LogoutWin.document.write('<input name="zone" type="hidden" value="<?=\$cpzone;?>" />');
+ LogoutWin.document.write('<input name="logout" type="submit" value="Logout" />');
+ LogoutWin.document.write('</form>');
+ LogoutWin.document.write('</div></body>');
+ LogoutWin.document.write('</html>');
+ LogoutWin.document.close();
+}
+
+document.location.href="<?=\$my_redirurl;?>";
+//]]>
+</script>
+</body>
+</html>
+
+EOD;
+ }
+
+ $fd = @fopen("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html", "w");
+ if ($fd) {
+ fwrite($fd, $logouttext);
+ fclose($fd);
+ }
+ unset($logouttext);
+
+ /* write elements */
+ captiveportal_write_elements();
+
+ /* kill any running mini_httpd */
+ killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
+
+ /* start up the webserving daemon */
+ captiveportal_init_webgui_zone($cpcfg);
+
+ /* Kill any existing prunecaptiveportal processes */
+ if (file_exists("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid")) {
+ killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
+ }
+
+ /* start pruning process (interval defaults to 60 seconds) */
+ mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/cp_prunedb_{$cpzone}.pid " .
+ "/etc/rc.prunecaptiveportal {$cpzone}");
+
+ /* generate radius server database */
+ unlink_if_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db");
+ captiveportal_init_radius_servers();
+
+ if (platform_booting()) {
+ /* send Accounting-On to server */
+ captiveportal_send_server_accounting();
+ echo "done\n";
+ }
+
+ } else {
+ killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
+ killbypid("{$g['varrun_path']}/cp_prunedb_{$cpzone}.pid");
+ @unlink("{$g['varetc_path']}/captiveportal_{$cpzone}.html");
+ @unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html");
+ @unlink("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html");
+
+ captiveportal_radius_stop_all();
+
+ /* send Accounting-Off to server */
+ if (!platform_booting()) {
+ captiveportal_send_server_accounting(true);
+ }
+
+ /* remove old information */
+ unlink_if_exists("{$g['vardb_path']}/captiveportal{$cpzone}.db");
+ unlink_if_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db");
+ unlink_if_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules");
+ /* Release allocated pipes for this zone */
+ captiveportal_free_dnrules();
+
+ mwexec("/sbin/ipfw zone {$cpzoneid} destroy", true);
+
+ if (empty($config['captiveportal'])) {
+ set_single_sysctl("net.link.ether.ipfw", "0");
+ } else {
+ /* Deactivate ipfw(4) if not needed */
+ $cpactive = false;
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpkey => $cp) {
+ if (isset($cp['enable'])) {
+ $cpactive = true;
+ break;
+ }
+ }
+ }
+ if ($cpactive === false) {
+ set_single_sysctl("net.link.ether.ipfw", "0");
+ }
+ }
+ }
+
+ unlock($captiveportallck);
+
+ return 0;
+}
+
+function captiveportal_init_webgui() {
+ global $config, $cpzone;
+
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpkey => $cp) {
+ $cpzone = $cpkey;
+ captiveportal_init_webgui_zone($cp);
+ }
+ }
+}
+
+function captiveportal_init_webgui_zonename($zone) {
+ global $config, $cpzone;
+
+ if (isset($config['captiveportal'][$zone])) {
+ $cpzone = $zone;
+ captiveportal_init_webgui_zone($config['captiveportal'][$zone]);
+ }
+}
+
+function captiveportal_init_webgui_zone($cpcfg) {
+ global $g, $config, $cpzone;
+
+ if (!isset($cpcfg['enable'])) {
+ return;
+ }
+
+ if (isset($cpcfg['httpslogin'])) {
+ $cert = lookup_cert($cpcfg['certref']);
+ $crt = base64_decode($cert['crt']);
+ $key = base64_decode($cert['prv']);
+ $ca = ca_chain($cert);
+
+ /* generate lighttpd configuration */
+ if (!empty($cpcfg['listenporthttps'])) {
+ $listenporthttps = $cpcfg['listenporthttps'];
+ } else {
+ $listenporthttps = 8001 + $cpcfg['zoneid'];
+ }
+ system_generate_lighty_config("{$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal-SSL.conf",
+ $crt, $key, $ca, "lighty-{$cpzone}-CaptivePortal-SSL.pid", $listenporthttps, "/usr/local/captiveportal",
+ "cert-{$cpzone}-portal.pem", "ca-{$cpzone}-portal.pem", $cpzone);
+ }
+
+ /* generate lighttpd configuration */
+ if (!empty($cpcfg['listenporthttp'])) {
+ $listenporthttp = $cpcfg['listenporthttp'];
+ } else {
+ $listenporthttp = 8000 + $cpcfg['zoneid'];
+ }
+ system_generate_lighty_config("{$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal.conf",
+ "", "", "", "lighty-{$cpzone}-CaptivePortal.pid", $listenporthttp, "/usr/local/captiveportal",
+ "", "", $cpzone);
+
+ @unlink("{$g['varrun']}/lighty-{$cpzone}-CaptivePortal.pid");
+ /* attempt to start lighttpd */
+ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal.conf");
+
+ /* fire up https instance */
+ if (isset($cpcfg['httpslogin'])) {
+ @unlink("{$g['varrun']}/lighty-{$cpzone}-CaptivePortal-SSL.pid");
+ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-{$cpzone}-CaptivePortal-SSL.conf");
+ }
+}
+
+function captiveportal_init_rules_byinterface($interface) {
+ global $cpzone, $cpzoneid, $config;
+
+ if (!is_array($config['captiveportal'])) {
+ return;
+ }
+
+ foreach ($config['captiveportal'] as $cpkey => $cp) {
+ $cpzone = $cpkey;
+ $cpzoneid = $cp['zoneid'];
+ $cpinterfaces = explode(",", $cp['interface']);
+ if (in_array($interface, $cpinterfaces)) {
+ captiveportal_init_rules();
+ break;
+ }
+ }
+}
+
+/* reinit will disconnect all users, be careful! */
+function captiveportal_init_rules($reinit = false) {
+ global $config, $g, $cpzone, $cpzoneid;
+
+ if (!isset($config['captiveportal'][$cpzone]['enable'])) {
+ return;
+ }
+
+ captiveportal_load_modules();
+ mwexec("/sbin/ipfw zone {$cpzoneid} create", true);
+
+ /* Cleanup so nothing is leaked */
+ captiveportal_free_dnrules();
+ unlink_if_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules");
+
+ $cpips = array();
+ $ifaces = get_configured_interface_list();
+ $cpinterfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
+ $firsttime = 0;
+ foreach ($cpinterfaces as $cpifgrp) {
+ if (!isset($ifaces[$cpifgrp])) {
+ continue;
+ }
+ $tmpif = get_real_interface($cpifgrp);
+ if (!empty($tmpif)) {
+ $cpipm = get_interface_ip($cpifgrp);
+ if (is_ipaddr($cpipm)) {
+ $cpips[] = $cpipm;
+ if (!is_array($config['virtualip']) || !is_array($config['virtualip']['vip'])) {
+ continue;
+ }
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if (($vip['interface'] == $cpifgrp) && (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias"))) {
+ $cpips[] = $vip['subnet'];
+ }
+ }
+ }
+ mwexec("/sbin/ipfw zone {$cpzoneid} madd {$tmpif}", true);
+ }
+ }
+ if (count($cpips) > 0) {
+ $cpactive = true;
+ } else {
+ return false;
+ }
+
+ if ($reinit == false) {
+ $captiveportallck = lock("captiveportal{$cpzone}");
+ }
+
+ $cprules = <<<EOD
+
+flush
+add 65291 allow pfsync from any to any
+add 65292 allow carp from any to any
+
+# layer 2: pass ARP
+add 65301 pass layer2 mac-type arp,rarp
+# pfsense requires for WPA
+add 65302 pass layer2 mac-type 0x888e,0x88c7
+# PPP Over Ethernet Session Stage/Discovery Stage
+add 65303 pass layer2 mac-type 0x8863,0x8864
+
+# layer 2: block anything else non-IP(v4/v6)
+add 65307 deny layer2 not mac-type ip,ipv6
+
+EOD;
+
+ $rulenum = 65310;
+ /* These tables contain host ips */
+ $cprules .= "add {$rulenum} pass ip from any to table(100) in\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pass ip from table(100) to any out\n";
+ $rulenum++;
+ $ips = "";
+ foreach ($cpips as $cpip) {
+ $cprules .= "table 100 add {$cpip}\n";
+ }
+ $cprules .= "table 100 add 255.255.255.255\n";
+ $cprules .= "add {$rulenum} pass ip from any to {$ips} in\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pass ip from {$ips} to any out\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pass icmp from {$ips} to any out icmptype 0\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pass icmp from any to {$ips} in icmptype 8 \n";
+ $rulenum++;
+ /* Allowed ips */
+ $cprules .= "add {$rulenum} pipe tablearg ip from table(3) to any in\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pipe tablearg ip from any to table(4) in\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pipe tablearg ip from table(3) to any out\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pipe tablearg ip from any to table(4) out\n";
+ $rulenum++;
+
+ /* Authenticated users rules. */
+ $cprules .= "add {$rulenum} pipe tablearg ip from table(1) to any in\n";
+ $rulenum++;
+ $cprules .= "add {$rulenum} pipe tablearg ip from any to table(2) out\n";
+ $rulenum++;
+
+ if (!empty($config['captiveportal'][$cpzone]['listenporthttp'])) {
+ $listenporthttp = $config['captiveportal'][$cpzone]['listenporthttp'];
+ } else {
+ $listenporthttp = 8000 + $cpzoneid;
+ }
+
+ if (isset($config['captiveportal'][$cpzone]['httpslogin'])) {
+ if (!empty($config['captiveportal'][$cpzone]['listenporthttps'])) {
+ $listenporthttps = $config['captiveportal'][$cpzone]['listenporthttps'];
+ } else {
+ $listenporthttps = 8001 + $cpzoneid;
+ }
+ if (!isset($config['captiveportal'][$cpzone]['nohttpsforwards'])) {
+ $cprules .= "add 65531 fwd 127.0.0.1,{$listenporthttps} tcp from any to any dst-port 443 in\n";
+ }
+ }
+
+ $cprules .= <<<EOD
+
+# redirect non-authenticated clients to captive portal
+add 65532 fwd 127.0.0.1,{$listenporthttp} tcp from any to any dst-port 80 in
+# let the responses from the captive portal web server back out
+add 65533 pass tcp from any to any out
+# block everything else
+add 65534 deny all from any to any
+
+EOD;
+
+ /* generate passthru mac database */
+ $cprules .= captiveportal_passthrumac_configure(true);
+ $cprules .= "\n";
+
+ /* allowed ipfw rules to make allowed ip work */
+ $cprules .= captiveportal_allowedip_configure();
+
+ /* allowed ipfw rules to make allowed hostnames work */
+ $cprules .= captiveportal_allowedhostname_configure();
+
+ /* load rules */
+ file_put_contents("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", $cprules);
+ mwexec("/sbin/ipfw -x {$cpzoneid} -q {$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", true);
+ //@unlink("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules");
+ unset($cprules);
+
+ if ($reinit == false) {
+ unlock($captiveportallck);
+ }
+}
+
+/*
+ * Remove clients that have been around for longer than the specified amount of time
+ * db file structure:
+ * timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time,interim_interval
+ * (password is in Base64 and only saved when reauthentication is enabled)
+ */
+function captiveportal_prune_old() {
+ global $g, $config, $cpzone, $cpzoneid;
+
+ if (empty($cpzone)) {
+ return;
+ }
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+ $vcpcfg = $config['voucher'][$cpzone];
+
+ /* check for expired entries */
+ $idletimeout = 0;
+ $timeout = 0;
+ if (!empty($cpcfg['timeout']) && is_numeric($cpcfg['timeout'])) {
+ $timeout = $cpcfg['timeout'] * 60;
+ }
+
+ if (!empty($cpcfg['idletimeout']) && is_numeric($cpcfg['idletimeout'])) {
+ $idletimeout = $cpcfg['idletimeout'] * 60;
+ }
+
+ /* Is there any job to do? */
+ if (!$timeout && !$idletimeout && !isset($cpcfg['reauthenticate']) &&
+ !isset($cpcfg['radiussession_timeout']) && !isset($vcpcfg['enable'])) {
+ return;
+ }
+
+ $radiussrvs = captiveportal_get_radius_servers();
+
+ /* Read database */
+ /* NOTE: while this can be simplified in non radius case keep as is for now */
+ $cpdb = captiveportal_read_db();
+
+ $unsetindexes = array();
+ $voucher_needs_sync = false;
+ /*
+ * Snapshot the time here to use for calculation to speed up the process.
+ * If something is missed next run will catch it!
+ */
+ $pruning_time = time();
+ $stop_time = $pruning_time;
+ foreach ($cpdb as $cpentry) {
+
+ $timedout = false;
+ $term_cause = 1;
+ if (empty($cpentry[11])) {
+ $cpentry[11] = 'first';
+ }
+ $radiusservers = $radiussrvs[$cpentry[11]];
+
+ /* hard timeout? */
+ if ($timeout) {
+ if (($pruning_time - $cpentry[0]) >= $timeout) {
+ $timedout = true;
+ $term_cause = 5; // Session-Timeout
+ }
+ }
+
+ /* Session-Terminate-Time */
+ if (!$timedout && !empty($cpentry[9])) {
+ if ($pruning_time >= $cpentry[9]) {
+ $timedout = true;
+ $term_cause = 5; // Session-Timeout
+ }
+ }
+
+ /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
+ $uidletimeout = (is_numeric($cpentry[8])) ? $cpentry[8] : $idletimeout;
+ /* if an idle timeout is specified, get last activity timestamp from ipfw */
+ if (!$timedout && $uidletimeout > 0) {
+ $lastact = captiveportal_get_last_activity($cpentry[2], $cpentry[3]);
+ /* If the user has logged on but not sent any traffic they will never be logged out.
+ * We "fix" this by setting lastact to the login timestamp.
+ */
+ $lastact = $lastact ? $lastact : $cpentry[0];
+ if ($lastact && (($pruning_time - $lastact) >= $uidletimeout)) {
+ $timedout = true;
+ $term_cause = 4; // Idle-Timeout
+ $stop_time = $lastact; // Entry added to comply with WISPr
+ }
+ }
+
+ /* if vouchers are configured, activate session timeouts */
+ if (!$timedout && isset($vcpcfg['enable']) && !empty($cpentry[7])) {
+ if ($pruning_time >= ($cpentry[0] + $cpentry[7])) {
+ $timedout = true;
+ $term_cause = 5; // Session-Timeout
+ $voucher_needs_sync = true;
+ }
+ }
+
+ /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
+ if (!$timedout && isset($cpcfg['radiussession_timeout']) && !empty($cpentry[7])) {
+ if ($pruning_time >= ($cpentry[0] + $cpentry[7])) {
+ $timedout = true;
+ $term_cause = 5; // Session-Timeout
+ }
+ }
+
+ if ($timedout) {
+ captiveportal_disconnect($cpentry, $radiusservers, $term_cause, $stop_time);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT");
+ $unsetindexes[] = $cpentry[5];
+ }
+
+ /* do periodic RADIUS reauthentication? */
+ if (!$timedout && !empty($radiusservers)) {
+ if (isset($cpcfg['radacct_enable'])) {
+ if ($cpcfg['reauthenticateacct'] == "stopstart") {
+ /* stop and restart accounting */
+ RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $cpentry[0], // start time
+ $radiusservers,
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
+ 10); // NAS Request
+ $clientsn = (is_ipaddrv6($cpentry[2])) ? 128 : 32;
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XZEROENTRY, 1, $cpentry[2], $clientsn, $cpentry[3]);
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XZEROENTRY, 2, $cpentry[2], $clientsn, $cpentry[3]);
+ RADIUS_ACCOUNTING_START($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $radiusservers,
+ $cpentry[2], // clientip
+ $cpentry[3]); // clientmac
+ } else if ($cpcfg['reauthenticateacct'] == "interimupdate") {
+ $session_time = $pruning_time - $cpentry[0];
+ if (!empty($cpentry[10]) && $cpentry[10] > 60) {
+ $interval = $cpentry[10];
+ } else {
+ $interval = 0;
+ }
+ $past_interval_min = ($session_time > $interval);
+ if ($interval != 0) {
+ $within_interval = ($session_time % $interval >= 0 && $session_time % $interval <= 59);
+ }
+ if ($interval === 0 || ($interval > 0 && $past_interval_min && $within_interval)) {
+ RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $cpentry[0], // start time
+ $radiusservers,
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
+ 10, // NAS Request
+ true); // Interim Updates
+ }
+ }
+ }
+
+ /* check this user against RADIUS again */
+ if (isset($cpcfg['reauthenticate'])) {
+ $auth_list = RADIUS_AUTHENTICATION($cpentry[4], // username
+ base64_decode($cpentry[6]), // password
+ $radiusservers,
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
+ $cpentry[1]); // ruleno
+ if ($auth_list['auth_val'] == 3) {
+ captiveportal_disconnect($cpentry, $radiusservers, 17);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
+ $unsetindexes[] = $cpentry[5];
+ } else if ($auth_list['auth_val'] == 2) {
+ captiveportal_reapply_attributes($cpentry, $auth_list);
+ }
+ }
+ }
+ }
+ unset($cpdb);
+
+ captiveportal_prune_old_automac();
+
+ if ($voucher_needs_sync == true) {
+ /* Trigger a sync of the vouchers on config */
+ send_event("service sync vouchers");
+ }
+
+ /* write database */
+ if (!empty($unsetindexes)) {
+ captiveportal_remove_entries($unsetindexes);
+ }
+}
+
+function captiveportal_prune_old_automac() {
+ global $g, $config, $cpzone, $cpzoneid;
+
+ if (is_array($config['captiveportal'][$cpzone]['passthrumac']) && isset($config['captiveportal'][$cpzone]['passthrumacaddusername'])) {
+ $tmpvoucherdb = array();
+ $macrules = "";
+ $writecfg = false;
+ foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $eid => $emac) {
+ if ($emac['logintype'] == "voucher") {
+ if (isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) {
+ if (isset($tmpvoucherdb[$emac['username']])) {
+ $temac = $config['captiveportal'][$cpzone]['passthrumac'][$tmpvoucherdb[$emac['username']]];
+ $ruleno = captiveportal_get_ipfw_passthru_ruleno($temac['mac']);
+ $pipeno = captiveportal_get_dn_passthru_ruleno($temac['mac']);
+ if ($ruleno) {
+ captiveportal_free_ipfw_ruleno($ruleno);
+ $macrules .= "delete {$ruleno}";
+ ++$ruleno;
+ $macrules .= "delete {$ruleno}";
+ }
+ if ($pipeno) {
+ captiveportal_free_dn_ruleno($pipeno);
+ $macrules .= "pipe delete {$pipeno}\n";
+ ++$pipeno;
+ $macrules .= "pipe delete {$pipeno}\n";
+ }
+ $writecfg = true;
+ captiveportal_logportalauth($temac['username'], $temac['mac'], $temac['ip'], "DUPLICATE {$temac['username']} LOGIN - TERMINATING OLD SESSION");
+ unset($config['captiveportal'][$cpzone]['passthrumac'][$tmpvoucherdb[$emac['username']]]);
+ }
+ $tmpvoucherdb[$emac['username']] = $eid;
+ }
+ if (voucher_auth($emac['username']) <= 0) {
+ $ruleno = captiveportal_get_ipfw_passthru_ruleno($emac['mac']);
+ $pipeno = captiveportal_get_dn_passthru_ruleno($emac['mac']);
+ if ($ruleno) {
+ captiveportal_free_ipfw_ruleno($ruleno);
+ $macrules .= "delete {$ruleno}";
+ ++$ruleno;
+ $macrules .= "delete {$ruleno}";
+ }
+ if ($pipeno) {
+ captiveportal_free_dn_ruleno($pipeno);
+ $macrules .= "pipe delete {$pipeno}\n";
+ ++$pipeno;
+ $macrules .= "pipe delete {$pipeno}\n";
+ }
+ $writecfg = true;
+ captiveportal_logportalauth($emac['username'], $emac['mac'], $emac['ip'], "EXPIRED {$emac['username']} LOGIN - TERMINATING SESSION");
+ unset($config['captiveportal'][$cpzone]['passthrumac'][$eid]);
+ }
+ }
+ }
+ unset($tmpvoucherdb);
+ if (!empty($macrules)) {
+ @file_put_contents("{$g['tmp_path']}/macentry.prunerules.tmp", $macrules);
+ unset($macrules);
+ mwexec("/sbin/ipfw -x {$cpzoneid} -q {$g['tmp_path']}/macentry.prunerules.tmp");
+ }
+ if ($writecfg === true) {
+ write_config("Prune session for auto-added macs");
+ }
+ }
+}
+
+/* remove a single client according to the DB entry */
+function captiveportal_disconnect($dbent, $radiusservers, $term_cause = 1, $stop_time = null) {
+ global $g, $config, $cpzone, $cpzoneid;
+
+ $stop_time = (empty($stop_time)) ? time() : $stop_time;
+
+ /* this client needs to be deleted - remove ipfw rules */
+ if (isset($config['captiveportal'][$cpzone]['radacct_enable']) && !empty($radiusservers)) {
+ RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
+ $dbent[4], // username
+ $dbent[5], // sessionid
+ $dbent[0], // start time
+ $radiusservers,
+ $dbent[2], // clientip
+ $dbent[3], // clientmac
+ $term_cause, // Acct-Terminate-Cause
+ false,
+ $stop_time);
+ }
+
+ if (is_ipaddr($dbent[2])) {
+ /* Delete client's ip entry from tables 1 and 2. */
+ $clientsn = (is_ipaddrv6($dbent[2])) ? 128 : 32;
+ pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XDEL, 1, $dbent[2], $clientsn, $dbent[3]);
+ pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XDEL, 2, $dbent[2], $clientsn, $dbent[3]);
+ /* XXX: Redundant?! Ensure all pf(4) states are killed. */
+ $_gb = @pfSense_kill_states($dbent[2]);
+ $_gb = @pfSense_kill_srcstates($dbent[2]);
+ }
+
+ /*
+ * These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
+ * We could get an error if the pipe doesn't exist but everything should still be fine
+ */
+ if (!empty($dbent[1])) {
+ $_gb = @pfSense_pipe_action("pipe delete {$dbent[1]}");
+ $_gb = @pfSense_pipe_action("pipe delete " . ($dbent[1]+1));
+
+ /* Release the ruleno so it can be reallocated to new clients. */
+ captiveportal_free_dn_ruleno($dbent[1]);
+ }
+
+ // XMLRPC Call over to the master Voucher node
+ if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
+ $syncip = $config['voucher'][$cpzone]['vouchersyncdbip'];
+ $syncport = $config['voucher'][$cpzone]['vouchersyncport'];
+ $syncpass = $config['voucher'][$cpzone]['vouchersyncpass'];
+ $vouchersyncusername = $config['voucher'][$cpzone]['vouchersyncusername'];
+ $remote_status = xmlrpc_sync_voucher_disconnect($dbent, $syncip, $syncport, $syncpass, $vouchersyncusername, $term_cause, $stop_time);
+ }
+
+}
+
+/* remove a single client by sessionid */
+function captiveportal_disconnect_client($sessionid, $term_cause = 1, $logoutReason = "LOGOUT") {
+ global $g, $config;
+
+ $radiusservers = captiveportal_get_radius_servers();
+
+ /* read database */
+ $result = captiveportal_read_db("WHERE sessionid = '{$sessionid}'");
+
+ /* find entry */
+ if (!empty($result)) {
+ captiveportal_write_db("DELETE FROM captiveportal WHERE sessionid = '{$sessionid}'");
+
+ foreach ($result as $cpentry) {
+ if (empty($cpentry[11])) {
+ $cpentry[11] = 'first';
+ }
+ captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], $term_cause);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");
+ }
+ unset($result);
+ }
+}
+
+/* send RADIUS acct stop for all current clients */
+function captiveportal_radius_stop_all() {
+ global $config, $cpzone;
+
+ if (!isset($config['captiveportal'][$cpzone]['radacct_enable'])) {
+ return;
+ }
+
+ $radiusservers = captiveportal_get_radius_servers();
+ if (!empty($radiusservers)) {
+ $cpdb = captiveportal_read_db();
+ foreach ($cpdb as $cpentry) {
+ if (empty($cpentry[11])) {
+ $cpentry[11] = 'first';
+ }
+ if (!empty($radiusservers[$cpentry[11]])) {
+ RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
+ $cpentry[4], // username
+ $cpentry[5], // sessionid
+ $cpentry[0], // start time
+ $radiusservers[$cpentry[11]],
+ $cpentry[2], // clientip
+ $cpentry[3], // clientmac
+ 7); // Admin Reboot
+ }
+ }
+ }
+}
+
+function captiveportal_passthrumac_configure_entry($macent, $pipeinrule = false) {
+ global $config, $g, $cpzone;
+
+ $bwUp = 0;
+ if (!empty($macent['bw_up'])) {
+ $bwUp = $macent['bw_up'];
+ } else if (!empty($config['captiveportal'][$cpzone]['bwdefaultup'])) {
+ $bwUp = $config['captiveportal'][$cpzone]['bwdefaultup'];
+ }
+ $bwDown = 0;
+ if (!empty($macent['bw_down'])) {
+ $bwDown = $macent['bw_down'];
+ } else if (!empty($config['captiveportal'][$cpzone]['bwdefaultdn'])) {
+ $bwDown = $config['captiveportal'][$cpzone]['bwdefaultdn'];
+ }
+
+ $ruleno = captiveportal_get_next_ipfw_ruleno();
+
+ if ($macent['action'] == 'pass') {
+ $rules = "";
+ $pipeno = captiveportal_get_next_dn_ruleno();
+
+ $pipeup = $pipeno;
+ if ($pipeinrule == true) {
+ $_gb = @pfSense_pipe_action("pipe {$pipeno} config bw {$bwUp}Kbit/s queue 100 buckets 16");
+ } else {
+ $rules .= "pipe {$pipeno} config bw {$bwUp}Kbit/s queue 100 buckets 16\n";
+ }
+
+ $pipedown = $pipeno + 1;
+ if ($pipeinrule == true) {
+ $_gb = @pfSense_pipe_action("pipe {$pipedown} config bw {$bwDown}Kbit/s queue 100 buckets 16");
+ } else {
+ $rules .= "pipe {$pipedown} config bw {$bwDown}Kbit/s queue 100 buckets 16\n";
+ }
+
+ $rules .= "add {$ruleno} pipe {$pipeup} ip from any to any MAC any {$macent['mac']}\n";
+ $ruleno++;
+ $rules .= "add {$ruleno} pipe {$pipedown} ip from any to any MAC {$macent['mac']} any\n";
+ }
+
+ return $rules;
+}
+
+function captiveportal_passthrumac_delete_entry($macent) {
+ $rules = "";
+
+ if ($macent['action'] == 'pass') {
+ $ruleno = captiveportal_get_ipfw_passthru_ruleno($macent['mac']);
+
+ if (!$ruleno) {
+ return $rules;
+ }
+
+ captiveportal_free_ipfw_ruleno($ruleno);
+
+ $rules .= "delete {$ruleno}\n";
+ $rules .= "delete " . ++$ruleno . "\n";
+
+ $pipeno = captiveportal_get_dn_passthru_ruleno($macent['mac']);
+
+ if (!empty($pipeno)) {
+ captiveportal_free_dn_ruleno($pipeno);
+ $rules .= "pipe delete " . $pipeno . "\n";
+ $rules .= "pipe delete " . ++$pipeno . "\n";
+ }
+ }
+
+ return $rules;
+}
+
+function captiveportal_passthrumac_configure($filename = false, $startindex = 0, $stopindex = 0) {
+ global $config, $g, $cpzone;
+
+ $rules = "";
+
+ if (is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
+ if ($stopindex > 0) {
+ $fd = fopen($filename, "w");
+ for ($idx = $startindex; $idx <= $stopindex; $idx++) {
+ if (isset($config['captiveportal'][$cpzone]['passthrumac'][$idx])) {
+ $rules = captiveportal_passthrumac_configure_entry($config['captiveportal'][$cpzone]['passthrumac'][$idx]);
+ fwrite($fd, $rules);
+ }
+ }
+ fclose($fd);
+
+ return;
+ } else {
+ $nentries = count($config['captiveportal'][$cpzone]['passthrumac']);
+ if ($nentries > 2000) {
+ $nloops = $nentries / 1000;
+ $remainder= $nentries % 1000;
+ for ($i = 0; $i < $nloops; $i++) {
+ mwexec_bg("/usr/local/sbin/fcgicli -f /etc/rc.captiveportal_configure_mac -d \"cpzone={$cpzone}&startidx=" . ($i * 1000) . "&stopidx=" . ((($i+1) * 1000) - 1) . "\"");
+ }
+ if ($remainder > 0) {
+ mwexec_bg("/usr/local/sbin/fcgicli -f /etc/rc.captiveportal_configure_mac -d \"cpzone={$cpzone}&startidx=" . ($i * 1000) . "&stopidx=" . (($i* 1000) + $remainder) ."\"");
+ }
+ } else {
+ foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $macent) {
+ $rules .= captiveportal_passthrumac_configure_entry($macent, true);
+ }
+ }
+ }
+ }
+
+ return $rules;
+}
+
+function captiveportal_passthrumac_findbyname($username) {
+ global $config, $cpzone;
+
+ if (is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
+ foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $macent) {
+ if ($macent['username'] == $username) {
+ return $macent;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * table (3=IN)/(4=OUT) hold allowed ip's without bw limits
+ */
+function captiveportal_allowedip_configure_entry($ipent, $ishostname = false) {
+ global $g;
+
+ /* Instead of copying this entire function for something
+ * easy such as hostname vs ip address add this check
+ */
+ if ($ishostname === true) {
+ if (!platform_booting()) {
+ $ipaddress = gethostbyname($ipent['hostname']);
+ if (!is_ipaddr($ipaddress)) {
+ return;
+ }
+ } else {
+ $ipaddress = "";
+ }
+ } else {
+ $ipaddress = $ipent['ip'];
+ }
+
+ $rules = "";
+ $cp_filterdns_conf = "";
+ $enBwup = 0;
+ if (!empty($ipent['bw_up'])) {
+ $enBwup = intval($ipent['bw_up']);
+ } else if (!empty($config['captiveportal'][$cpzone]['bwdefaultup'])) {
+ $enBwup = $config['captiveportal'][$cpzone]['bwdefaultup'];
+ }
+ $enBwdown = 0;
+ if (!empty($ipent['bw_down'])) {
+ $enBwdown = intval($ipent['bw_down']);
+ } else if (!empty($config['captiveportal'][$cpzone]['bwdefaultdn'])) {
+ $enBwdown = $config['captiveportal'][$cpzone]['bwdefaultdn'];
+ }
+
+ $pipeno = captiveportal_get_next_dn_ruleno();
+ $_gb = @pfSense_pipe_action("pipe {$pipeno} config bw {$enBwup}Kbit/s queue 100 buckets 16");
+ $pipedown = $pipeno + 1;
+ $_gb = @pfSense_pipe_action("pipe {$pipedown} config bw {$enBwdown}Kbit/s queue 100 buckets 16");
+ if ($ishostname === true) {
+ $cp_filterdns_conf .= "ipfw {$ipent['hostname']} 3 pipe {$pipeno}\n";
+ $cp_filterdns_conf .= "ipfw {$ipent['hostname']} 4 pipe {$pipedown}\n";
+ if (!is_ipaddr($ipaddress)) {
+ return array("", $cp_filterdns_conf);
+ }
+ }
+ $subnet = "";
+ if (!empty($ipent['sn'])) {
+ $subnet = "/{$ipent['sn']}";
+ }
+ $rules .= "table 3 add {$ipaddress}{$subnet} {$pipeno}\n";
+ $rules .= "table 4 add {$ipaddress}{$subnet} {$pipedown}\n";
+
+ if ($ishostname === true) {
+ return array($rules, $cp_filterdns_conf);
+ } else {
+ return $rules;
+ }
+}
+
+function captiveportal_allowedhostname_configure() {
+ global $config, $g, $cpzone, $cpzoneid;
+
+ $rules = "";
+ if (is_array($config['captiveportal'][$cpzone]['allowedhostname'])) {
+ $rules = "\n# captiveportal_allowedhostname_configure()\n";
+ $cp_filterdns_conf = "";
+ foreach ($config['captiveportal'][$cpzone]['allowedhostname'] as $hostnameent) {
+ $tmprules = captiveportal_allowedip_configure_entry($hostnameent, true);
+ $rules .= $tmprules[0];
+ $cp_filterdns_conf .= $tmprules[1];
+ }
+ $cp_filterdns_filename = "{$g['varetc_path']}/filterdns-{$cpzone}-captiveportal.conf";
+ @file_put_contents($cp_filterdns_filename, $cp_filterdns_conf);
+ unset($cp_filterdns_conf);
+ if (isvalidpid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid")) {
+ sigkillbypid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid", "HUP");
+ } else {
+ mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid -i 300 -c {$cp_filterdns_filename} -y {$cpzoneid} -d 1");
+ }
+ } else {
+ killbypid("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid");
+ @unlink("{$g['varrun_path']}/filterdns-{$cpzone}-cpah.pid");
+ }
+
+ return $rules;
+}
+
+function captiveportal_allowedip_configure() {
+ global $config, $g, $cpzone;
+
+ $rules = "";
+ if (is_array($config['captiveportal'][$cpzone]['allowedip'])) {
+ foreach ($config['captiveportal'][$cpzone]['allowedip'] as $ipent) {
+ $rules .= captiveportal_allowedip_configure_entry($ipent);
+ }
+ }
+
+ return $rules;
+}
+
+/* get last activity timestamp given client IP address */
+function captiveportal_get_last_activity($ip, $mac = NULL, $table = 1) {
+ global $cpzoneid;
+
+ $ipfwoutput = pfSense_ipfw_getTablestats($cpzoneid, IP_FW_TABLE_XLISTENTRY, $table, $ip, $mac);
+ /* Reading only from one of the tables is enough of approximation. */
+ if (is_array($ipfwoutput)) {
+ /* Workaround for #46652 */
+ if ($ipfwoutput['packets'] > 0) {
+ return $ipfwoutput['timestamp'];
+ } else {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+function captiveportal_init_radius_servers() {
+ global $config, $g, $cpzone;
+
+ /* generate radius server database */
+ if ($config['captiveportal'][$cpzone]['radiusip'] &&
+ (!isset($config['captiveportal'][$cpzone]['auth_method']) || $config['captiveportal'][$cpzone]['auth_method'] == "radius")) {
+ $radiusip = $config['captiveportal'][$cpzone]['radiusip'];
+ $radiusip2 = ($config['captiveportal'][$cpzone]['radiusip2']) ? $config['captiveportal'][$cpzone]['radiusip2'] : null;
+ $radiusip3 = ($config['captiveportal'][$cpzone]['radiusip3']) ? $config['captiveportal'][$cpzone]['radiusip3'] : null;
+ $radiusip4 = ($config['captiveportal'][$cpzone]['radiusip4']) ? $config['captiveportal'][$cpzone]['radiusip4'] : null;
+
+ if ($config['captiveportal'][$cpzone]['radiusport']) {
+ $radiusport = $config['captiveportal'][$cpzone]['radiusport'];
+ } else {
+ $radiusport = 1812;
+ }
+ if ($config['captiveportal'][$cpzone]['radiusacctport']) {
+ $radiusacctport = $config['captiveportal'][$cpzone]['radiusacctport'];
+ } else {
+ $radiusacctport = 1813;
+ }
+ if ($config['captiveportal'][$cpzone]['radiusport2']) {
+ $radiusport2 = $config['captiveportal'][$cpzone]['radiusport2'];
+ } else {
+ $radiusport2 = 1812;
+ }
+ if ($config['captiveportal'][$cpzone]['radiusport3']) {
+ $radiusport3 = $config['captiveportal'][$cpzone]['radiusport3'];
+ } else {
+ $radiusport3 = 1812;
+ }
+ if ($config['captiveportal'][$cpzone]['radiusport4']) {
+ $radiusport4 = $config['captiveportal'][$cpzone]['radiusport4'];
+ } else {
+ $radiusport4 = 1812;
+ }
+
+ $radiuskey = $config['captiveportal'][$cpzone]['radiuskey'];
+ $radiuskey2 = $config['captiveportal'][$cpzone]['radiuskey2'];
+ $radiuskey3 = $config['captiveportal'][$cpzone]['radiuskey3'];
+ $radiuskey4 = $config['captiveportal'][$cpzone]['radiuskey4'];
+
+ $cprdsrvlck = lock("captiveportalradius{$cpzone}", LOCK_EX);
+ $fd = @fopen("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db", "w");
+ if (!$fd) {
+ captiveportal_syslog("Error: cannot open radius DB file in captiveportal_configure().\n");
+ unlock($cprdsrvlck);
+ return 1;
+ }
+ if (isset($radiusip)) {
+ fwrite($fd, $radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . ",first");
+ }
+ if (isset($radiusip2)) {
+ fwrite($fd, "\n" . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2 . ",first");
+ }
+ if (isset($radiusip3)) {
+ fwrite($fd, "\n" . $radiusip3 . "," . $radiusport3 . "," . $radiusacctport . "," . $radiuskey3 . ",second");
+ }
+ if (isset($radiusip4)) {
+ fwrite($fd, "\n" . $radiusip4 . "," . $radiusport4 . "," . $radiusacctport . "," . $radiuskey4 . ",second");
+ }
+
+ fclose($fd);
+ unlock($cprdsrvlck);
+ }
+}
+
+/* read RADIUS servers into array */
+function captiveportal_get_radius_servers() {
+ global $g, $cpzone;
+
+ $cprdsrvlck = lock("captiveportalradius{$cpzone}");
+ if (file_exists("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db")) {
+ $radiusservers = array();
+ $cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius_{$cpzone}.db",
+ FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if ($cpradiusdb) {
+ foreach ($cpradiusdb as $cpradiusentry) {
+ $line = trim($cpradiusentry);
+ if ($line) {
+ $radsrv = array();
+ list($radsrv['ipaddr'], $radsrv['port'], $radsrv['acctport'], $radsrv['key'], $context) = explode(",", $line);
+ }
+ if (empty($context)) {
+ if (!is_array($radiusservers['first'])) {
+ $radiusservers['first'] = array();
+ }
+ $radiusservers['first'] = $radsrv;
+ } else {
+ if (!is_array($radiusservers[$context])) {
+ $radiusservers[$context] = array();
+ }
+ $radiusservers[$context][] = $radsrv;
+ }
+ }
+ }
+ unlock($cprdsrvlck);
+ return $radiusservers;
+ }
+
+ unlock($cprdsrvlck);
+ return false;
+}
+
+/* log successful captive portal authentication to syslog */
+/* part of this code from php.net */
+function captiveportal_logportalauth($user, $mac, $ip, $status, $message = null) {
+ // Log it
+ if (!$message) {
+ $message = "{$status}: {$user}, {$mac}, {$ip}";
+ } else {
+ $message = trim($message);
+ $message = "{$status}: {$user}, {$mac}, {$ip}, {$message}";
+ }
+ captiveportal_syslog($message);
+}
+
+/* log simple messages to syslog */
+function captiveportal_syslog($message) {
+ global $cpzone;
+
+ $message = trim($message);
+ $message = "Zone: {$cpzone} - {$message}";
+ openlog("logportalauth", LOG_PID, LOG_LOCAL4);
+ // Log it
+ syslog(LOG_INFO, $message);
+ closelog();
+}
+
+function radius($username, $password, $clientip, $clientmac, $type, $radiusctx = null) {
+ global $g, $config, $cpzoneid;
+
+ $pipeno = captiveportal_get_next_dn_ruleno();
+
+ /* If the pool is empty, return appropriate message and fail authentication */
+ if (empty($pipeno)) {
+ $auth_list = array();
+ $auth_list['auth_val'] = 1;
+ $auth_list['error'] = "System reached maximum login capacity";
+ return $auth_list;
+ }
+
+ $radiusservers = captiveportal_get_radius_servers();
+
+ if (is_null($radiusctx)) {
+ $radiusctx = 'first';
+ }
+
+ $auth_list = RADIUS_AUTHENTICATION($username,
+ $password,
+ $radiusservers[$radiusctx],
+ $clientip,
+ $clientmac,
+ $pipeno);
+
+ if ($auth_list['auth_val'] == 2) {
+ captiveportal_logportalauth($username, $clientmac, $clientip, $type);
+ $sessionid = portal_allow($clientip,
+ $clientmac,
+ $username,
+ $password,
+ $auth_list,
+ $pipeno,
+ $radiusctx);
+ } else {
+ captiveportal_free_dn_ruleno($pipeno);
+ }
+
+ return $auth_list;
+}
+
+function captiveportal_opendb() {
+ global $g, $cpzone;
+
+ $db_path = "{$g['vardb_path']}/captiveportal{$cpzone}.db";
+ $createquery = "CREATE TABLE IF NOT EXISTS captiveportal (" .
+ "allow_time INTEGER, pipeno INTEGER, ip TEXT, mac TEXT, username TEXT, " .
+ "sessionid TEXT, bpassword TEXT, session_timeout INTEGER, idle_timeout INTEGER, " .
+ "session_terminate_time INTEGER, interim_interval INTEGER, radiusctx TEXT); " .
+ "CREATE UNIQUE INDEX IF NOT EXISTS idx_active ON captiveportal (sessionid, username); " .
+ "CREATE INDEX IF NOT EXISTS user ON captiveportal (username); " .
+ "CREATE INDEX IF NOT EXISTS ip ON captiveportal (ip); " .
+ "CREATE INDEX IF NOT EXISTS starttime ON captiveportal (allow_time)";
+
+ try {
+ $DB = new SQLite3($db_path);
+ } catch (Exception $e) {
+ captiveportal_syslog("Could not open {$db_path} as an sqlite database for {$cpzone}. Error message: " . $e->getMessage() . " -- Trying again.");
+ unlink_if_exists($db_path);
+ try {
+ $DB = new SQLite3($db_path);
+ } catch (Exception $e) {
+ captiveportal_syslog("Still could not open {$db_path} as an sqlite database for {$cpzone}. Error message: " . $e->getMessage() . " -- Remove the database file manually and ensure there is enough free space.");
+ return;
+ }
+ }
+
+ if (!$DB) {
+ captiveportal_syslog("Could not open {$db_path} as an sqlite database for {$cpzone}. Error message: {$DB->lastErrorMsg()}. Trying again.");
+ unlink_if_exists($db_path);
+ $DB = new SQLite3($db_path);
+ if (!$DB) {
+ captiveportal_syslog("Still could not open {$db_path} as an sqlite database for {$cpzone}. Error message: {$DB->lastErrorMsg()}. Remove the database file manually and ensure there is enough free space.");
+ return;
+ }
+ }
+
+ if (! $DB->exec($createquery)) {
+ captiveportal_syslog("Error during table {$cpzone} creation. Error message: {$DB->lastErrorMsg()}. Resetting and trying again.");
+
+ /* If unable to initialize the database, reset and try again. */
+ $DB->close();
+ unset($DB);
+ unlink_if_exists($db_path);
+ $DB = new SQLite3($db_path);
+ if ($DB->exec($createquery)) {
+ captiveportal_syslog("Successfully reinitialized tables for {$cpzone} -- database has been reset.");
+ } else {
+ captiveportal_syslog("Still unable to create tables for {$cpzone}. Error message: {$DB->lastErrorMsg()}. Remove the database file manually and try again.");
+ }
+ }
+
+ return $DB;
+}
+
+/* read captive portal DB into array */
+function captiveportal_read_db($query = "") {
+ $cpdb = array();
+
+ $DB = captiveportal_opendb();
+ if ($DB) {
+ $response = $DB->query("SELECT * FROM captiveportal {$query}");
+ if ($response != FALSE) {
+ while ($row = $response->fetchArray()) {
+ $cpdb[] = $row;
+ }
+ }
+ $DB->close();
+ }
+
+ return $cpdb;
+}
+
+function captiveportal_remove_entries($remove) {
+
+ if (!is_array($remove) || empty($remove)) {
+ return;
+ }
+
+ $query = "DELETE FROM captiveportal WHERE sessionid in (";
+ foreach ($remove as $idx => $unindex) {
+ $query .= "'{$unindex}'";
+ if ($idx < (count($remove) - 1)) {
+ $query .= ",";
+ }
+ }
+ $query .= ")";
+ captiveportal_write_db($query);
+}
+
+/* write captive portal DB */
+function captiveportal_write_db($queries) {
+ global $g;
+
+ if (is_array($queries)) {
+ $query = implode(";", $queries);
+ } else {
+ $query = $queries;
+ }
+
+ $DB = captiveportal_opendb();
+ if ($DB) {
+ $DB->exec("BEGIN TRANSACTION");
+ $result = $DB->exec($query);
+ if (!$result) {
+ captiveportal_syslog("Trying to modify DB returned error: {$DB->lastErrorMsg()}");
+ } else {
+ $DB->exec("END TRANSACTION");
+ }
+ $DB->close();
+ return $result;
+ } else {
+ return true;
+ }
+}
+
+function captiveportal_write_elements() {
+ global $g, $config, $cpzone;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+
+ if (!is_dir($g['captiveportal_element_path'])) {
+ @mkdir($g['captiveportal_element_path']);
+ }
+
+ if (is_array($cpcfg['element'])) {
+ conf_mount_rw();
+ foreach ($cpcfg['element'] as $data) {
+ if (!@file_put_contents("{$g['captiveportal_element_path']}/{$data['name']}", base64_decode($data['content']))) {
+ printf(gettext("Error: cannot open '%s' in captiveportal_write_elements()%s"), $data['name'], "\n");
+ return 1;
+ }
+ if (!file_exists("{$g['captiveportal_path']}/{$data['name']}")) {
+ @symlink("{$g['captiveportal_element_path']}/{$data['name']}", "{$g['captiveportal_path']}/{$data['name']}");
+ }
+ }
+ conf_mount_ro();
+ }
+
+ return 0;
+}
+
+function captiveportal_free_dnrules($rulenos_start = 2000, $rulenos_range_max = 64500) {
+ global $cpzone;
+
+ $cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
+ if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
+ $ridx = $rulenos_start;
+ while ($ridx < $rulenos_range_max) {
+ if ($rules[$ridx] == $cpzone) {
+ $rules[$ridx] = false;
+ $ridx++;
+ $rules[$ridx] = false;
+ $ridx++;
+ } else {
+ $ridx += 2;
+ }
+ }
+ file_put_contents("{$g['vardb_path']}/captiveportaldn.rules", serialize($rules));
+ unset($rules);
+ }
+ unlock($cpruleslck);
+}
+
+function captiveportal_get_next_dn_ruleno($rulenos_start = 2000, $rulenos_range_max = 64500) {
+ global $config, $g, $cpzone;
+
+ $cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
+ $ruleno = 0;
+ if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
+ $ridx = $rulenos_start;
+ while ($ridx < $rulenos_range_max) {
+ if (empty($rules[$ridx])) {
+ $ruleno = $ridx;
+ $rules[$ridx] = $cpzone;
+ $ridx++;
+ $rules[$ridx] = $cpzone;
+ break;
+ } else {
+ $ridx += 2;
+ }
+ }
+ } else {
+ $rules = array_pad(array(), $rulenos_range_max, false);
+ $ruleno = $rulenos_start;
+ $rules[$rulenos_start] = $cpzone;
+ $rulenos_start++;
+ $rules[$rulenos_start] = $cpzone;
+ }
+ file_put_contents("{$g['vardb_path']}/captiveportaldn.rules", serialize($rules));
+ unlock($cpruleslck);
+ unset($rules);
+
+ return $ruleno;
+}
+
+function captiveportal_free_dn_ruleno($ruleno) {
+ global $config, $g;
+
+ $cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
+ if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
+ $rules[$ruleno] = false;
+ $ruleno++;
+ $rules[$ruleno] = false;
+ file_put_contents("{$g['vardb_path']}/captiveportaldn.rules", serialize($rules));
+ unset($rules);
+ }
+ unlock($cpruleslck);
+}
+
+function captiveportal_get_dn_passthru_ruleno($value) {
+ global $config, $g, $cpzone, $cpzoneid;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+ if (!isset($cpcfg['enable'])) {
+ return NULL;
+ }
+
+ $cpruleslck = lock("captiveportalrulesdn", LOCK_EX);
+ $ruleno = NULL;
+ if (file_exists("{$g['vardb_path']}/captiveportaldn.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportaldn.rules"));
+ unset($output);
+ $_gb = exec("/sbin/ipfw -x {$cpzoneid} show | /usr/bin/grep " . escapeshellarg($value) . " | /usr/bin/grep -v grep | /usr/bin/awk '{print $5}' | /usr/bin/head -n 1", $output);
+ $ruleno = intval($output[0]);
+ if (!$rules[$ruleno]) {
+ $ruleno = NULL;
+ }
+ unset($rules);
+ }
+ unlock($cpruleslck);
+
+ return $ruleno;
+}
+
+/*
+ * This function will calculate the lowest free firewall ruleno
+ * within the range specified based on the actual logged on users
+ *
+ */
+function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2, $rulenos_range_max = 64500) {
+ global $config, $g, $cpzone;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+ if (!isset($cpcfg['enable'])) {
+ return NULL;
+ }
+
+ $cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
+ $ruleno = 0;
+ if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
+ $ridx = $rulenos_start;
+ while ($ridx < $rulenos_range_max) {
+ if (empty($rules[$ridx])) {
+ $ruleno = $ridx;
+ $rules[$ridx] = $cpzone;
+ $ridx++;
+ $rules[$ridx] = $cpzone;
+ break;
+ } else {
+ /*
+ * This allows our traffic shaping pipes to be the in pipe the same as ruleno
+ * and the out pipe ruleno + 1.
+ */
+ $ridx += 2;
+ }
+ }
+ } else {
+ $rules = array_pad(array(), $rulenos_range_max, false);
+ $ruleno = $rulenos_start;
+ $rules[$rulenos_start] = $cpzone;
+ $rulenos_start++;
+ $rules[$rulenos_start] = $cpzone;
+ }
+ file_put_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules", serialize($rules));
+ unlock($cpruleslck);
+ unset($rules);
+
+ return $ruleno;
+}
+
+function captiveportal_free_ipfw_ruleno($ruleno) {
+ global $config, $g, $cpzone;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+ if (!isset($cpcfg['enable'])) {
+ return NULL;
+ }
+
+ $cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
+ if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
+ $rules[$ruleno] = false;
+ $ruleno++;
+ $rules[$ruleno] = false;
+ file_put_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules", serialize($rules));
+ unset($rules);
+ }
+ unlock($cpruleslck);
+}
+
+function captiveportal_get_ipfw_passthru_ruleno($value) {
+ global $config, $g, $cpzone, $cpzoneid;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+ if (!isset($cpcfg['enable'])) {
+ return NULL;
+ }
+
+ $cpruleslck = lock("captiveportalrules{$cpzone}", LOCK_EX);
+ $ruleno = NULL;
+ if (file_exists("{$g['vardb_path']}/captiveportal_{$cpzone}.rules")) {
+ $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal_{$cpzone}.rules"));
+ unset($output);
+ $_gb = exec("/sbin/ipfw -x {$cpzoneid} show | /usr/bin/grep " . escapeshellarg($value) . " | /usr/bin/grep -v grep | /usr/bin/awk '{print $1}' | /usr/bin/head -n 1", $output);
+ $ruleno = intval($output[0]);
+ if (!$rules[$ruleno]) {
+ $ruleno = NULL;
+ }
+ unset($rules);
+ }
+ unlock($cpruleslck);
+
+ return $ruleno;
+}
+
+/**
+ * This function will calculate the traffic produced by a client
+ * based on its firewall rule
+ *
+ * Point of view: NAS
+ *
+ * Input means: from the client
+ * Output means: to the client
+ *
+ */
+
+function getVolume($ip, $mac = NULL) {
+ global $config, $cpzone, $cpzoneid;
+
+ $reverse = empty($config['captiveportal'][$cpzone]['reverseacct']) ? false : true;
+ $volume = array();
+ // Initialize vars properly, since we don't want NULL vars
+ $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
+
+ $ipfw = pfSense_ipfw_getTablestats($cpzoneid, IP_FW_TABLE_XLISTENTRY, 1, $ip, $mac);
+ if (is_array($ipfw)) {
+ if ($reverse) {
+ $volume['output_pkts'] = $ipfw['packets'];
+ $volume['output_bytes'] = $ipfw['bytes'];
+ }
+ else {
+ $volume['input_pkts'] = $ipfw['packets'];
+ $volume['input_bytes'] = $ipfw['bytes'];
+ }
+ }
+
+ $ipfw = pfSense_ipfw_getTablestats($cpzoneid, IP_FW_TABLE_XLISTENTRY, 2, $ip, $mac);
+ if (is_array($ipfw)) {
+ if ($reverse) {
+ $volume['input_pkts'] = $ipfw['packets'];
+ $volume['input_bytes'] = $ipfw['bytes'];
+ }
+ else {
+ $volume['output_pkts'] = $ipfw['packets'];
+ $volume['output_bytes'] = $ipfw['bytes'];
+ }
+ }
+
+ return $volume;
+}
+
+/**
+ * Get the NAS-IP-Address based on the current wan address
+ *
+ * Use functions in interfaces.inc to find this out
+ *
+ */
+
+function getNasIP() {
+ global $config, $cpzone;
+
+ if (empty($config['captiveportal'][$cpzone]['radiussrcip_attribute'])) {
+ $nasIp = get_interface_ip();
+ } else {
+ if (is_ipaddr($config['captiveportal'][$cpzone]['radiussrcip_attribute'])) {
+ $nasIp = $config['captiveportal'][$cpzone]['radiussrcip_attribute'];
+ } else {
+ $nasIp = get_interface_ip($config['captiveportal'][$cpzone]['radiussrcip_attribute']);
+ }
+ }
+
+ if (!is_ipaddr($nasIp)) {
+ $nasIp = "0.0.0.0";
+ }
+
+ return $nasIp;
+}
+
+function portal_ip_from_client_ip($cliip) {
+ global $config, $cpzone;
+
+ $isipv6 = is_ipaddrv6($cliip);
+ $interfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
+ foreach ($interfaces as $cpif) {
+ if ($isipv6) {
+ $ip = get_interface_ipv6($cpif);
+ $sn = get_interface_subnetv6($cpif);
+ } else {
+ $ip = get_interface_ip($cpif);
+ $sn = get_interface_subnet($cpif);
+ }
+ if (ip_in_subnet($cliip, "{$ip}/{$sn}")) {
+ return $ip;
+ }
+ }
+
+ $inet = ($isipv6) ? '-inet6' : '-inet';
+ $iface = exec_command("/sbin/route -n get {$inet} {$cliip} | /usr/bin/awk '/interface/ { print \$2; };'");
+ $iface = trim($iface, "\n");
+ if (!empty($iface)) {
+ $ip = ($isipv6) ? find_interface_ipv6($iface) : find_interface_ip($iface);
+ if (is_ipaddr($ip)) {
+ return $ip;
+ }
+ }
+
+ // doesn't match up to any particular interface
+ // so let's set the portal IP to what PHP says
+ // the server IP issuing the request is.
+ // allows same behavior as 1.2.x where IP isn't
+ // in the subnet of any CP interface (static routes, etc.)
+ // rather than forcing to DNS hostname resolution
+ $ip = $_SERVER['SERVER_ADDR'];
+ if (is_ipaddr($ip)) {
+ return $ip;
+ }
+
+ return false;
+}
+
+function portal_hostname_from_client_ip($cliip) {
+ global $config, $cpzone;
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+
+ if (isset($cpcfg['httpslogin'])) {
+ $listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 8001);
+ $ourhostname = $cpcfg['httpsname'];
+
+ if ($listenporthttps != 443) {
+ $ourhostname .= ":" . $listenporthttps;
+ }
+ } else {
+ $listenporthttp = $cpcfg['listenporthttp'] ? $cpcfg['listenporthttp'] : ($cpcfg['zoneid'] + 8000);
+ $ifip = portal_ip_from_client_ip($cliip);
+ if (!$ifip) {
+ $ourhostname = "{$config['system']['hostname']}.{$config['system']['domain']}";
+ } else {
+ $ourhostname = (is_ipaddrv6($ifip)) ? "[{$ifip}]" : "{$ifip}";
+ }
+
+ if ($listenporthttp != 80) {
+ $ourhostname .= ":" . $listenporthttp;
+ }
+ }
+
+ return $ourhostname;
+}
+
+/* functions move from index.php */
+
+function portal_reply_page($redirurl, $type = null, $message = null, $clientmac = null, $clientip = null, $username = null, $password = null) {
+ global $g, $config, $cpzone;
+
+ /* Get captive portal layout */
+ if ($type == "redir") {
+ header("Location: {$redirurl}");
+ return;
+ } else if ($type == "login") {
+ $htmltext = get_include_contents("{$g['varetc_path']}/captiveportal_{$cpzone}.html");
+ } else {
+ $htmltext = get_include_contents("{$g['varetc_path']}/captiveportal-{$cpzone}-error.html");
+ }
+
+ $cpcfg = $config['captiveportal'][$cpzone];
+
+ /* substitute the PORTAL_REDIRURL variable */
+ if ($cpcfg['preauthurl']) {
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", "{$cpcfg['preauthurl']}", $htmltext);
+ $htmltext = str_replace("#PORTAL_REDIRURL#", "{$cpcfg['preauthurl']}", $htmltext);
+ }
+
+ /* substitute other variables */
+ $ourhostname = portal_hostname_from_client_ip($clientip);
+ $protocol = (isset($cpcfg['httpslogin'])) ? 'https://' : 'http://';
+ $htmltext = str_replace("\$PORTAL_ACTION\$", "{$protocol}{$ourhostname}/", $htmltext);
+ $htmltext = str_replace("#PORTAL_ACTION#", "{$protocol}{$ourhostname}/", $htmltext);
+
+ $htmltext = str_replace("\$PORTAL_ZONE\$", htmlspecialchars($cpzone), $htmltext);
+ $htmltext = str_replace("\$PORTAL_REDIRURL\$", htmlspecialchars($redirurl), $htmltext);
+ $htmltext = str_replace("\$PORTAL_MESSAGE\$", htmlspecialchars($message), $htmltext);
+ $htmltext = str_replace("\$CLIENT_MAC\$", htmlspecialchars($clientmac), $htmltext);
+ $htmltext = str_replace("\$CLIENT_IP\$", htmlspecialchars($clientip), $htmltext);
+
+ // Special handling case for captive portal master page so that it can be ran
+ // through the PHP interpreter using the include method above. We convert the
+ // $VARIABLE$ case to #VARIABLE# in /etc/inc/captiveportal.inc before writing out.
+ $htmltext = str_replace("#PORTAL_ZONE#", htmlspecialchars($cpzone), $htmltext);
+ $htmltext = str_replace("#PORTAL_REDIRURL#", htmlspecialchars($redirurl), $htmltext);
+ $htmltext = str_replace("#PORTAL_MESSAGE#", htmlspecialchars($message), $htmltext);
+ $htmltext = str_replace("#CLIENT_MAC#", htmlspecialchars($clientmac), $htmltext);
+ $htmltext = str_replace("#CLIENT_IP#", htmlspecialchars($clientip), $htmltext);
+ $htmltext = str_replace("#USERNAME#", htmlspecialchars($username), $htmltext);
+ $htmltext = str_replace("#PASSWORD#", htmlspecialchars($password), $htmltext);
+
+ echo $htmltext;
+}
+
+function portal_mac_radius($clientmac, $clientip) {
+ global $config, $cpzone;
+
+ $radmac_secret = $config['captiveportal'][$cpzone]['radmac_secret'];
+
+ /* authentication against the radius server */
+ $username = mac_format($clientmac);
+ $auth_list = radius($username, $radmac_secret, $clientip, $clientmac, "MACHINE LOGIN");
+ if ($auth_list['auth_val'] == 2) {
+ return TRUE;
+ }
+
+ if (!empty($auth_list['url_redirection'])) {
+ portal_reply_page($auth_list['url_redirection'], "redir");
+ }
+
+ return FALSE;
+}
+
+function captiveportal_reapply_attributes($cpentry, $attributes) {
+ global $config, $cpzone, $g;
+
+ if (isset($config['captiveportal'][$cpzone]['peruserbw'])) {
+ $dwfaultbw_up = !empty($config['captiveportal'][$cpzone]['bwdefaultup']) ? $config['captiveportal'][$cpzone]['bwdefaultup'] : 0;
+ $dwfaultbw_down = !empty($config['captiveportal'][$cpzone]['bwdefaultdn']) ? $config['captiveportal'][$cpzone]['bwdefaultdn'] : 0;
+ } else {
+ $dwfaultbw_up = $dwfaultbw_down = 0;
+ }
+ $bw_up = !empty($attributes['bw_up']) ? round(intval($attributes['bw_up'])/1000, 2) : $dwfaultbw_up;
+ $bw_down = !empty($attributes['bw_down']) ? round(intval($attributes['bw_down'])/1000, 2) : $dwfaultbw_down;
+ $bw_up_pipeno = $cpentry[1];
+ $bw_down_pipeno = $cpentry[1]+1;
+
+ $_gb = @pfSense_pipe_action("pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100 buckets 16");
+ $_gb = @pfSense_pipe_action("pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100 buckets 16");
+ //captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "RADIUS_BANDWIDTH_REAPPLY", "{$bw_up}/{$bw_down}");
+
+ unset($bw_up_pipeno, $bw_down_pipeno, $bw_up, $bw_down);
+}
+
+function portal_allow($clientip, $clientmac, $username, $password = null, $attributes = null, $pipeno = null, $radiusctx = null) {
+ global $redirurl, $g, $config, $type, $passthrumac, $_POST, $cpzone, $cpzoneid;
+
+ // Ensure we create an array if we are missing attributes
+ if (!is_array($attributes)) {
+ $attributes = array();
+ }
+
+ unset($sessionid);
+
+ /* Do not allow concurrent login execution. */
+ $cpdblck = lock("captiveportaldb{$cpzone}", LOCK_EX);
+
+ if ($attributes['voucher']) {
+ $remaining_time = $attributes['session_timeout'];
+ }
+
+ $writecfg = false;
+ /* Find an existing session */
+ if ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && $passthrumac) {
+ if (isset($config['captiveportal'][$cpzone]['passthrumacadd'])) {
+ $mac = captiveportal_passthrumac_findbyname($username);
+ if (!empty($mac)) {
+ if ($_POST['replacemacpassthru']) {
+ foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $idx => $macent) {
+ if ($macent['mac'] == $mac['mac']) {
+ $macrules = "";
+ $ruleno = captiveportal_get_ipfw_passthru_ruleno($mac['mac']);
+ $pipeno = captiveportal_get_dn_passthru_ruleno($mac['mac']);
+ if ($ruleno) {
+ captiveportal_free_ipfw_ruleno($ruleno);
+ $macrules .= "delete {$ruleno}\n";
+ ++$ruleno;
+ $macrules .= "delete {$ruleno}\n";
+ }
+ if ($pipeno) {
+ captiveportal_free_dn_ruleno($pipeno);
+ $macrules .= "pipe delete {$pipeno}\n";
+ ++$pipeno;
+ $macrules .= "pipe delete {$pipeno}\n";
+ }
+ unset($config['captiveportal'][$cpzone]['passthrumac'][$idx]);
+ $mac['action'] = 'pass';
+ $mac['mac'] = $clientmac;
+ $config['captiveportal'][$cpzone]['passthrumac'][] = $mac;
+ $macrules .= captiveportal_passthrumac_configure_entry($mac);
+ file_put_contents("{$g['tmp_path']}/macentry_{$cpzone}.rules.tmp", $macrules);
+ mwexec("/sbin/ipfw -x {$cpzoneid} -q {$g['tmp_path']}/macentry_{$cpzone}.rules.tmp");
+ $writecfg = true;
+ $sessionid = true;
+ break;
+ }
+ }
+ } else {
+ portal_reply_page($redirurl, "error", "Username: {$username} is already authenticated using another MAC address.",
+ $clientmac, $clientip, $username, $password);
+ unlock($cpdblck);
+ return;
+ }
+ }
+ }
+ }
+
+ /* read in client database */
+ $query = "WHERE ip = '{$clientip}'";
+ $tmpusername = strtolower($username);
+ if (isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) {
+ $query .= " OR (username != 'unauthenticated' AND lower(username) = '{$tmpusername}')";
+ }
+ $cpdb = captiveportal_read_db($query);
+
+ /* Snapshot the timestamp */
+ $allow_time = time();
+ $radiusservers = captiveportal_get_radius_servers();
+ $unsetindexes = array();
+ if (is_null($radiusctx)) {
+ $radiusctx = 'first';
+ }
+
+ foreach ($cpdb as $cpentry) {
+ if (empty($cpentry[11])) {
+ $cpentry[11] = 'first';
+ }
+ /* on the same ip */
+ if ($cpentry[2] == $clientip) {
+ if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac) {
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING OLD SESSION");
+ } else {
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
+ }
+ $sessionid = $cpentry[5];
+ break;
+ } elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
+ // user logged in with an active voucher. Check for how long and calculate
+ // how much time we can give him (voucher credit - used time)
+ $remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
+ if ($remaining_time < 0) { // just in case.
+ $remaining_time = 0;
+ }
+
+ /* This user was already logged in so we disconnect the old one */
+ captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
+ $unsetindexes[] = $cpentry[5];
+ break;
+ } elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
+ /* on the same username */
+ if (strcasecmp($cpentry[4], $username) == 0) {
+ /* This user was already logged in so we disconnect the old one */
+ captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
+ $unsetindexes[] = $cpentry[5];
+ break;
+ }
+ }
+ }
+ unset($cpdb);
+
+ if (!empty($unsetindexes)) {
+ captiveportal_remove_entries($unsetindexes);
+ }
+
+ if ($attributes['voucher'] && $remaining_time <= 0) {
+ return 0; // voucher already used and no time left
+ }
+
+ if (!isset($sessionid)) {
+ /* generate unique session ID */
+ $tod = gettimeofday();
+ $sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
+
+ if ($passthrumac) {
+ $mac = array();
+ $mac['action'] = 'pass';
+ $mac['mac'] = $clientmac;
+ $mac['ip'] = $clientip; /* Used only for logging */
+ if (isset($config['captiveportal'][$cpzone]['passthrumacaddusername'])) {
+ $mac['username'] = $username;
+ if ($attributes['voucher']) {
+ $mac['logintype'] = "voucher";
+ }
+ }
+ if ($username == "unauthenticated") {
+ $mac['descr'] = "Auto-added";
+ } else {
+ $mac['descr'] = "Auto-added for user {$username}";
+ }
+ if (!empty($bw_up)) {
+ $mac['bw_up'] = $bw_up;
+ }
+ if (!empty($bw_down)) {
+ $mac['bw_down'] = $bw_down;
+ }
+ if (!is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
+ $config['captiveportal'][$cpzone]['passthrumac'] = array();
+ }
+ $config['captiveportal'][$cpzone]['passthrumac'][] = $mac;
+ unlock($cpdblck);
+ $macrules = captiveportal_passthrumac_configure_entry($mac);
+ file_put_contents("{$g['tmp_path']}/macentry_{$cpzone}.rules.tmp", $macrules);
+ mwexec("/sbin/ipfw -x {$cpzoneid} -q {$g['tmp_path']}/macentry_{$cpzone}.rules.tmp");
+ $writecfg = true;
+ } else {
+ /* See if a pipeno is passed, if not start sessions because this means there isn't one atm */
+ if (is_null($pipeno)) {
+ $pipeno = captiveportal_get_next_dn_ruleno();
+ }
+
+ /* if the pool is empty, return appropriate message and exit */
+ if (is_null($pipeno)) {
+ portal_reply_page($redirurl, "error", "System reached maximum login capacity");
+ log_error("Zone: {$cpzone} - WARNING! Captive portal has reached maximum login capacity");
+ unlock($cpdblck);
+ return;
+ }
+
+ if (isset($config['captiveportal'][$cpzone]['peruserbw'])) {
+ $dwfaultbw_up = !empty($config['captiveportal'][$cpzone]['bwdefaultup']) ? $config['captiveportal'][$cpzone]['bwdefaultup'] : 0;
+ $dwfaultbw_down = !empty($config['captiveportal'][$cpzone]['bwdefaultdn']) ? $config['captiveportal'][$cpzone]['bwdefaultdn'] : 0;
+ } else {
+ $dwfaultbw_up = $dwfaultbw_down = 0;
+ }
+ $bw_up = !empty($attributes['bw_up']) ? round(intval($attributes['bw_up'])/1000, 2) : $dwfaultbw_up;
+ $bw_down = !empty($attributes['bw_down']) ? round(intval($attributes['bw_down'])/1000, 2) : $dwfaultbw_down;
+
+ $bw_up_pipeno = $pipeno;
+ $bw_down_pipeno = $pipeno + 1;
+ //$bw_up /= 1000; // Scale to Kbit/s
+ $_gb = @pfSense_pipe_action("pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100 buckets 16");
+ $_gb = @pfSense_pipe_action("pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100 buckets 16");
+
+ $clientsn = (is_ipaddrv6($clientip)) ? 128 : 32;
+ if (!isset($config['captiveportal'][$cpzone]['nomacfilter'])) {
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XADD, 1, $clientip, $clientsn, $clientmac, $bw_up_pipeno);
+ } else {
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XADD, 1, $clientip, $clientsn, NULL, $bw_up_pipeno);
+ }
+
+ if (!isset($config['captiveportal'][$cpzone]['nomacfilter'])) {
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XADD, 2, $clientip, $clientsn, $clientmac, $bw_down_pipeno);
+ } else {
+ $_gb = @pfSense_ipfw_Tableaction($cpzoneid, IP_FW_TABLE_XADD, 2, $clientip, $clientsn, NULL, $bw_down_pipeno);
+ }
+
+ if ($attributes['voucher']) {
+ $attributes['session_timeout'] = $remaining_time;
+ }
+
+ /* handle empty attributes */
+ $session_timeout = (!empty($attributes['session_timeout'])) ? $attributes['session_timeout'] : 'NULL';
+ $idle_timeout = (!empty($attributes['idle_timeout'])) ? $attributes['idle_timeout'] : 'NULL';
+ $session_terminate_time = (!empty($attributes['session_terminate_time'])) ? $attributes['session_terminate_time'] : 'NULL';
+ $interim_interval = (!empty($attributes['interim_interval'])) ? $attributes['interim_interval'] : 'NULL';
+
+ /* escape username */
+ $safe_username = SQLite3::escapeString($username);
+
+ /* encode password in Base64 just in case it contains commas */
+ $bpassword = base64_encode($password);
+ $insertquery = "INSERT INTO captiveportal (allow_time, pipeno, ip, mac, username, sessionid, bpassword, session_timeout, idle_timeout, session_terminate_time, interim_interval, radiusctx) ";
+ $insertquery .= "VALUES ({$allow_time}, {$pipeno}, '{$clientip}', '{$clientmac}', '{$safe_username}', '{$sessionid}', '{$bpassword}', ";
+ $insertquery .= "{$session_timeout}, {$idle_timeout}, {$session_terminate_time}, {$interim_interval}, '{$radiusctx}')";
+
+ /* store information to database */
+ captiveportal_write_db($insertquery);
+ unlock($cpdblck);
+ unset($insertquery, $bpassword);
+
+ if (isset($config['captiveportal'][$cpzone]['radacct_enable']) && !empty($radiusservers[$radiusctx])) {
+ $acct_val = RADIUS_ACCOUNTING_START($pipeno, $username, $sessionid, $radiusservers[$radiusctx], $clientip, $clientmac);
+ if ($acct_val == 1) {
+ captiveportal_logportalauth($username, $clientmac, $clientip, $type, "RADIUS ACCOUNTING FAILED");
+ }
+ }
+ }
+ } else {
+ /* NOTE: #3062-11 If the pipeno has been allocated free it to not DoS the CP and maintain proper operation as in radius() case */
+ if (!is_null($pipeno)) {
+ captiveportal_free_dn_ruleno($pipeno);
+ }
+
+ unlock($cpdblck);
+ }
+
+ if ($writecfg == true) {
+ write_config();
+ }
+
+ /* redirect user to desired destination */
+ if (!empty($attributes['url_redirection'])) {
+ $my_redirurl = $attributes['url_redirection'];
+ } else if (!empty($redirurl)) {
+ $my_redirurl = $redirurl;
+ } else if (!empty($config['captiveportal'][$cpzone]['redirurl'])) {
+ $my_redirurl = $config['captiveportal'][$cpzone]['redirurl'];
+ }
+
+ if (isset($config['captiveportal'][$cpzone]['logoutwin_enable']) && !$passthrumac) {
+ $ourhostname = portal_hostname_from_client_ip($clientip);
+ $protocol = (isset($config['captiveportal'][$cpzone]['httpslogin'])) ? 'https://' : 'http://';
+ $logouturl = "{$protocol}{$ourhostname}/";
+
+ if (isset($attributes['reply_message'])) {
+ $message = $attributes['reply_message'];
+ } else {
+ $message = 0;
+ }
+
+ include("{$g['varetc_path']}/captiveportal-{$cpzone}-logout.html");
+
+ } else {
+ portal_reply_page($my_redirurl, "redir", "Just redirect the user.");
+ }
+
+ return $sessionid;
+}
+
+
+/*
+ * Used for when pass-through credits are enabled.
+ * Returns true when there was at least one free login to deduct for the MAC.
+ * Expired entries are removed as they are seen.
+ * Active entries are updated according to the configuration.
+ */
+function portal_consume_passthrough_credit($clientmac) {
+ global $config, $cpzone;
+
+ if (!empty($config['captiveportal'][$cpzone]['freelogins_count']) && is_numeric($config['captiveportal'][$cpzone]['freelogins_count'])) {
+ $freeloginscount = $config['captiveportal'][$cpzone]['freelogins_count'];
+ } else {
+ return false;
+ }
+
+ if (!empty($config['captiveportal'][$cpzone]['freelogins_resettimeout']) && is_numeric($config['captiveportal'][$cpzone]['freelogins_resettimeout'])) {
+ $resettimeout = $config['captiveportal'][$cpzone]['freelogins_resettimeout'];
+ } else {
+ return false;
+ }
+
+ if ($freeloginscount < 1 || $resettimeout <= 0 || !$clientmac) {
+ return false;
+ }
+
+ $updatetimeouts = isset($config['captiveportal'][$cpzone]['freelogins_updatetimeouts']);
+
+ /*
+ * Read database of used MACs. Lines are a comma-separated list
+ * of the time, MAC, then the count of pass-through credits remaining.
+ */
+ $usedmacs = captiveportal_read_usedmacs_db();
+
+ $currenttime = time();
+ $found = false;
+ foreach ($usedmacs as $key => $usedmac) {
+ $usedmac = explode(",", $usedmac);
+
+ if ($usedmac[1] == $clientmac) {
+ if ($usedmac[0] + ($resettimeout * 3600) > $currenttime) {
+ if ($usedmac[2] < 1) {
+ if ($updatetimeouts) {
+ $usedmac[0] = $currenttime;
+ unset($usedmacs[$key]);
+ $usedmacs[] = implode(",", $usedmac);
+ captiveportal_write_usedmacs_db($usedmacs);
+ }
+
+ return false;
+ } else {
+ $usedmac[2] -= 1;
+ $usedmacs[$key] = implode(",", $usedmac);
+ }
+
+ $found = true;
+ } else {
+ unset($usedmacs[$key]);
+ }
+
+ break;
+ } else if ($usedmac[0] + ($resettimeout * 3600) <= $currenttime) {
+ unset($usedmacs[$key]);
+ }
+ }
+
+ if (!$found) {
+ $usedmac = array($currenttime, $clientmac, $freeloginscount - 1);
+ $usedmacs[] = implode(",", $usedmac);
+ }
+
+ captiveportal_write_usedmacs_db($usedmacs);
+ return true;
+}
+
+function captiveportal_read_usedmacs_db() {
+ global $g, $cpzone;
+
+ $cpumaclck = lock("captiveusedmacs{$cpzone}");
+ if (file_exists("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db")) {
+ $usedmacs = file("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!$usedmacs) {
+ $usedmacs = array();
+ }
+ } else {
+ $usedmacs = array();
+ }
+
+ unlock($cpumaclck);
+ return $usedmacs;
+}
+
+function captiveportal_write_usedmacs_db($usedmacs) {
+ global $g, $cpzone;
+
+ $cpumaclck = lock("captiveusedmacs{$cpzone}", LOCK_EX);
+ @file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs_{$cpzone}.db", implode("\n", $usedmacs));
+ unlock($cpumaclck);
+}
+
+function captiveportal_blocked_mac($mac) {
+ global $config, $g, $cpzone;
+
+ if (empty($mac) || !is_macaddr($mac)) {
+ return false;
+ }
+
+ if (!is_array($config['captiveportal'][$cpzone]['passthrumac'])) {
+ return false;
+ }
+
+ foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $passthrumac) {
+ if (($passthrumac['action'] == 'block') &&
+ ($passthrumac['mac'] == strtolower($mac))) {
+ return true;
+ }
+ }
+
+ return false;
+
+}
+
+function captiveportal_send_server_accounting($off = false) {
+ global $cpzone, $config;
+
+ if (!isset($config['captiveportal'][$cpzone]['radacct_enable'])) {
+ return;
+ }
+ if ($off) {
+ $racct = new Auth_RADIUS_Acct_Off;
+ } else {
+ $racct = new Auth_RADIUS_Acct_On;
+ }
+ $radiusservers = captiveportal_get_radius_servers();
+ if (empty($radiusservers)) {
+ return;
+ }
+ foreach ($radiusservers['first'] as $radsrv) {
+ // Add a new server to our instance
+ $racct->addServer($radsrv['ipaddr'], $radsrv['acctport'], $radsrv['key']);
+ }
+ if (PEAR::isError($racct->start())) {
+ $retvalue['acct_val'] = 1;
+ $retvalue['error'] = $racct->getMessage();
+
+ // If we encounter an error immediately stop this function and go back
+ $racct->close();
+ return $retvalue;
+ }
+ // Send request
+ $result = $racct->send();
+ // Evaluation of the response
+ // 5 -> Accounting-Response
+ // See RFC2866 for this.
+ if (PEAR::isError($result)) {
+ $retvalue['acct_val'] = 1;
+ $retvalue['error'] = $result->getMessage();
+ } else if ($result === true) {
+ $retvalue['acct_val'] = 5 ;
+ } else {
+ $retvalue['acct_val'] = 1 ;
+ }
+
+ $racct->close();
+ return $retvalue;
+}
+?>
diff --git a/src/etc/inc/certs.inc b/src/etc/inc/certs.inc
new file mode 100644
index 0000000..9c99952
--- /dev/null
+++ b/src/etc/inc/certs.inc
@@ -0,0 +1,867 @@
+<?php
+/* $Id$ */
+/*
+ certs.inc
+ Copyright (C) 2008 Shrew Soft Inc
+ Copyright (C) 2010 Jim Pingle <jimp@pfsense.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_MODULE: certificate_manager
+*/
+
+define("OPEN_SSL_CONF_PATH", "/etc/ssl/openssl.cnf");
+
+require_once("functions.inc");
+
+global $openssl_digest_algs;
+$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
+
+global $openssl_crl_status;
+$openssl_crl_status = array(
+ OCSP_REVOKED_STATUS_NOSTATUS => "No Status (default)",
+ OCSP_REVOKED_STATUS_UNSPECIFIED => "Unspecified",
+ OCSP_REVOKED_STATUS_KEYCOMPROMISE => "Key Compromise",
+ OCSP_REVOKED_STATUS_CACOMPROMISE => "CA Compromise",
+ OCSP_REVOKED_STATUS_AFFILIATIONCHANGED => "Affiliation Changed",
+ OCSP_REVOKED_STATUS_SUPERSEDED => "Superseded",
+ OCSP_REVOKED_STATUS_CESSATIONOFOPERATION => "Cessation of Operation",
+ OCSP_REVOKED_STATUS_CERTIFICATEHOLD => "Certificate Hold"
+);
+
+function & lookup_ca($refid) {
+ global $config;
+
+ if (is_array($config['ca'])) {
+ foreach ($config['ca'] as & $ca) {
+ if ($ca['refid'] == $refid) {
+ return $ca;
+ }
+ }
+ }
+
+ return false;
+}
+
+function & lookup_ca_by_subject($subject) {
+ global $config;
+
+ if (is_array($config['ca'])) {
+ foreach ($config['ca'] as & $ca) {
+ $ca_subject = cert_get_subject($ca['crt']);
+ if ($ca_subject == $subject) {
+ return $ca;
+ }
+ }
+ }
+
+ return false;
+}
+
+function & lookup_cert($refid) {
+ global $config;
+
+ if (is_array($config['cert'])) {
+ foreach ($config['cert'] as & $cert) {
+ if ($cert['refid'] == $refid) {
+ return $cert;
+ }
+ }
+ }
+
+ return false;
+}
+
+function & lookup_cert_by_name($name) {
+ global $config;
+ if (is_array($config['cert'])) {
+ foreach ($config['cert'] as & $cert) {
+ if ($cert['descr'] == $name) {
+ return $cert;
+ }
+ }
+ }
+}
+
+function & lookup_crl($refid) {
+ global $config;
+
+ if (is_array($config['crl'])) {
+ foreach ($config['crl'] as & $crl) {
+ if ($crl['refid'] == $refid) {
+ return $crl;
+ }
+ }
+ }
+
+ return false;
+}
+
+function ca_chain_array(& $cert) {
+ if ($cert['caref']) {
+ $chain = array();
+ $crt = lookup_ca($cert['caref']);
+ $chain[] = $crt;
+ while ($crt) {
+ $caref = $crt['caref'];
+ if ($caref) {
+ $crt = lookup_ca($caref);
+ } else {
+ $crt = false;
+ }
+ if ($crt) {
+ $chain[] = $crt;
+ }
+ }
+ return $chain;
+ }
+ return false;
+}
+
+function ca_chain(& $cert) {
+ if ($cert['caref']) {
+ $ca = "";
+ $cas = ca_chain_array($cert);
+ if (is_array($cas)) {
+ foreach ($cas as & $ca_cert) {
+ $ca .= base64_decode($ca_cert['crt']);
+ $ca .= "\n";
+ }
+ }
+ return $ca;
+ }
+ return "";
+}
+
+function ca_import(& $ca, $str, $key = "", $serial = 0) {
+ global $config;
+
+ $ca['crt'] = base64_encode($str);
+ if (!empty($key)) {
+ $ca['prv'] = base64_encode($key);
+ }
+ if (!empty($serial)) {
+ $ca['serial'] = $serial;
+ }
+ $subject = cert_get_subject($str, false);
+ $issuer = cert_get_issuer($str, false);
+
+ // Find my issuer unless self-signed
+ if ($issuer <> $subject) {
+ $issuer_crt =& lookup_ca_by_subject($issuer);
+ if ($issuer_crt) {
+ $ca['caref'] = $issuer_crt['refid'];
+ }
+ }
+
+ /* Correct if child certificate was loaded first */
+ if (is_array($config['ca'])) {
+ foreach ($config['ca'] as & $oca) {
+ $issuer = cert_get_issuer($oca['crt']);
+ if ($ca['refid'] <> $oca['refid'] && $issuer == $subject) {
+ $oca['caref'] = $ca['refid'];
+ }
+ }
+ }
+ if (is_array($config['cert'])) {
+ foreach ($config['cert'] as & $cert) {
+ $issuer = cert_get_issuer($cert['crt']);
+ if ($issuer == $subject) {
+ $cert['caref'] = $ca['refid'];
+ }
+ }
+ }
+ return true;
+}
+
+function ca_create(& $ca, $keylen, $lifetime, $dn, $digest_alg = "sha256") {
+
+ $args = array(
+ "x509_extensions" => "v3_ca",
+ "digest_alg" => $digest_alg,
+ "private_key_bits" => (int)$keylen,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA,
+ "encrypt_key" => false);
+
+ // generate a new key pair
+ $res_key = openssl_pkey_new($args);
+ if (!$res_key) {
+ return false;
+ }
+
+ // generate a certificate signing request
+ $res_csr = openssl_csr_new($dn, $res_key, $args);
+ if (!$res_csr) {
+ return false;
+ }
+
+ // self sign the certificate
+ $res_crt = openssl_csr_sign($res_csr, null, $res_key, $lifetime, $args);
+ if (!$res_crt) {
+ return false;
+ }
+
+ // export our certificate data
+ if (!openssl_pkey_export($res_key, $str_key) ||
+ !openssl_x509_export($res_crt, $str_crt)) {
+ return false;
+ }
+
+ // return our ca information
+ $ca['crt'] = base64_encode($str_crt);
+ $ca['prv'] = base64_encode($str_key);
+ $ca['serial'] = 0;
+
+ return true;
+}
+
+function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "sha256") {
+ // Create Intermediate Certificate Authority
+ $signing_ca =& lookup_ca($caref);
+ if (!$signing_ca) {
+ return false;
+ }
+
+ $signing_ca_res_crt = openssl_x509_read(base64_decode($signing_ca['crt']));
+ $signing_ca_res_key = openssl_pkey_get_private(array(0 => base64_decode($signing_ca['prv']) , 1 => ""));
+ if (!$signing_ca_res_crt || !$signing_ca_res_key) {
+ return false;
+ }
+ $signing_ca_serial = ++$signing_ca['serial'];
+
+ $args = array(
+ "x509_extensions" => "v3_ca",
+ "digest_alg" => $digest_alg,
+ "private_key_bits" => (int)$keylen,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA,
+ "encrypt_key" => false);
+
+ // generate a new key pair
+ $res_key = openssl_pkey_new($args);
+ if (!$res_key) {
+ return false;
+ }
+
+ // generate a certificate signing request
+ $res_csr = openssl_csr_new($dn, $res_key, $args);
+ if (!$res_csr) {
+ return false;
+ }
+
+ // Sign the certificate
+ $res_crt = openssl_csr_sign($res_csr, $signing_ca_res_crt, $signing_ca_res_key, $lifetime, $args, $signing_ca_serial);
+ if (!$res_crt) {
+ return false;
+ }
+
+ // export our certificate data
+ if (!openssl_pkey_export($res_key, $str_key) ||
+ !openssl_x509_export($res_crt, $str_crt)) {
+ return false;
+ }
+
+ // return our ca information
+ $ca['crt'] = base64_encode($str_crt);
+ $ca['prv'] = base64_encode($str_key);
+ $ca['serial'] = 0;
+
+ return true;
+}
+
+function cert_import(& $cert, $crt_str, $key_str) {
+
+ $cert['crt'] = base64_encode($crt_str);
+ $cert['prv'] = base64_encode($key_str);
+
+ $subject = cert_get_subject($crt_str, false);
+ $issuer = cert_get_issuer($crt_str, false);
+
+ // Find my issuer unless self-signed
+ if ($issuer <> $subject) {
+ $issuer_crt =& lookup_ca_by_subject($issuer);
+ if ($issuer_crt) {
+ $cert['caref'] = $issuer_crt['refid'];
+ }
+ }
+ return true;
+}
+
+function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $digest_alg = "sha256") {
+
+ $cert['type'] = $type;
+
+ if ($type != "self-signed") {
+ $cert['caref'] = $caref;
+ $ca =& lookup_ca($caref);
+ if (!$ca) {
+ return false;
+ }
+
+ $ca_str_crt = base64_decode($ca['crt']);
+ $ca_str_key = base64_decode($ca['prv']);
+ $ca_res_crt = openssl_x509_read($ca_str_crt);
+ $ca_res_key = openssl_pkey_get_private(array(0 => $ca_str_key, 1 => ""));
+ if (!$ca_res_key) {
+ return false;
+ }
+ $ca_serial = ++$ca['serial'];
+ }
+
+ switch ($type) {
+ case "ca":
+ $cert_type = "v3_ca";
+ break;
+ case "server":
+ case "self-signed":
+ $cert_type = "server";
+ break;
+ default:
+ $cert_type = "usr_cert";
+ break;
+ }
+
+ // in case of using Subject Alternative Names use other sections (with postfix '_san')
+ // pass subjectAltName over environment variable 'SAN'
+ if ($dn['subjectAltName']) {
+ putenv("SAN={$dn['subjectAltName']}"); // subjectAltName can be set _only_ via configuration file
+ $cert_type .= '_san';
+ unset($dn['subjectAltName']);
+ }
+
+ $args = array(
+ "x509_extensions" => $cert_type,
+ "digest_alg" => $digest_alg,
+ "private_key_bits" => (int)$keylen,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA,
+ "encrypt_key" => false);
+
+ // generate a new key pair
+ $res_key = openssl_pkey_new($args);
+ if (!$res_key) {
+ return false;
+ }
+
+ // If this is a self-signed cert, blank out the CA and sign with the cert's key
+ if ($type == "self-signed") {
+ $ca = null;
+ $ca_res_crt = null;
+ $ca_res_key = $res_key;
+ $ca_serial = 0;
+ $cert['type'] = "server";
+ }
+
+ // generate a certificate signing request
+ $res_csr = openssl_csr_new($dn, $res_key, $args);
+ if (!$res_csr) {
+ return false;
+ }
+
+ // sign the certificate using an internal CA
+ $res_crt = openssl_csr_sign($res_csr, $ca_res_crt, $ca_res_key, $lifetime,
+ $args, $ca_serial);
+ if (!$res_crt) {
+ return false;
+ }
+
+ // export our certificate data
+ if (!openssl_pkey_export($res_key, $str_key) ||
+ !openssl_x509_export($res_crt, $str_crt)) {
+ return false;
+ }
+
+ // return our certificate information
+ $cert['crt'] = base64_encode($str_crt);
+ $cert['prv'] = base64_encode($str_key);
+
+ return true;
+}
+
+function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
+
+ $args = array(
+ "x509_extensions" => "v3_req",
+ "digest_alg" => $digest_alg,
+ "private_key_bits" => (int)$keylen,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA,
+ "encrypt_key" => false);
+
+ // generate a new key pair
+ $res_key = openssl_pkey_new($args);
+ if (!$res_key) {
+ return false;
+ }
+
+ // generate a certificate signing request
+ $res_csr = openssl_csr_new($dn, $res_key, $args);
+ if (!$res_csr) {
+ return false;
+ }
+
+ // export our request data
+ if (!openssl_pkey_export($res_key, $str_key) ||
+ !openssl_csr_export($res_csr, $str_csr)) {
+ return false;
+ }
+
+ // return our request information
+ $cert['csr'] = base64_encode($str_csr);
+ $cert['prv'] = base64_encode($str_key);
+
+ return true;
+}
+
+function csr_complete(& $cert, $str_crt) {
+
+ // return our request information
+ $cert['crt'] = base64_encode($str_crt);
+ unset($cert['csr']);
+
+ return true;
+}
+
+function csr_get_subject($str_crt, $decode = true) {
+
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+
+ $components = openssl_csr_get_subject($str_crt);
+
+ if (empty($components) || !is_array($components)) {
+ return "unknown";
+ }
+
+ ksort($components);
+ foreach ($components as $a => $v) {
+ if (!strlen($subject)) {
+ $subject = "{$a}={$v}";
+ } else {
+ $subject = "{$a}={$v}, {$subject}";
+ }
+ }
+
+ return $subject;
+}
+
+function cert_get_subject($str_crt, $decode = true) {
+
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+
+ $inf_crt = openssl_x509_parse($str_crt);
+ $components = $inf_crt['subject'];
+
+ if (empty($components) || !is_array($components)) {
+ return "unknown";
+ }
+
+ ksort($components);
+ foreach ($components as $a => $v) {
+ if (is_array($v)) {
+ ksort($v);
+ foreach ($v as $w) {
+ $asubject = "{$a}={$w}";
+ $subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
+ }
+ } else {
+ $asubject = "{$a}={$v}";
+ $subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
+ }
+ }
+
+ return $subject;
+}
+
+function cert_get_subject_array($crt) {
+ $str_crt = base64_decode($crt);
+ $inf_crt = openssl_x509_parse($str_crt);
+ $components = $inf_crt['subject'];
+
+ if (!is_array($components)) {
+ return;
+ }
+
+ $subject_array = array();
+
+ foreach ($components as $a => $v) {
+ $subject_array[] = array('a' => $a, 'v' => $v);
+ }
+
+ return $subject_array;
+}
+
+function cert_get_subject_hash($crt) {
+ $str_crt = base64_decode($crt);
+ $inf_crt = openssl_x509_parse($str_crt);
+ return $inf_crt['subject'];
+}
+
+function cert_get_issuer($str_crt, $decode = true) {
+
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+
+ $inf_crt = openssl_x509_parse($str_crt);
+ $components = $inf_crt['issuer'];
+
+ if (empty($components) || !is_array($components)) {
+ return "unknown";
+ }
+
+ ksort($components);
+ foreach ($components as $a => $v) {
+ if (is_array($v)) {
+ ksort($v);
+ foreach ($v as $w) {
+ $aissuer = "{$a}={$w}";
+ $issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
+ }
+ } else {
+ $aissuer = "{$a}={$v}";
+ $issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
+ }
+ }
+
+ return $issuer;
+}
+
+/* this function works on x509 (crt), rsa key (prv), and req(csr) */
+function cert_get_modulus($str_crt, $decode = true, $type = "crt") {
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+
+ $modulus = "";
+ if (in_array($type, array("crt", "prv", "csr"))) {
+ $type = str_replace(array("crt", "prv", "csr"), array("x509", "rsa", "req"), $type);
+ $modulus = exec("echo \"{$str_crt}\" | openssl {$type} -noout -modulus");
+ }
+ return $modulus;
+}
+function csr_get_modulus($str_crt, $decode = true) {
+ return cert_get_modulus($str_crt, $decode, "csr");
+}
+
+function cert_get_purpose($str_crt, $decode = true) {
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+ $crt_details = openssl_x509_parse($str_crt);
+ $purpose = array();
+ $purpose['ca'] = (stristr($crt_details['extensions']['basicConstraints'], 'CA:TRUE') === false) ? 'No': 'Yes';
+ $purpose['server'] = ($crt_details['extensions']['nsCertType'] == "SSL Server") ? 'Yes': 'No';
+ return $purpose;
+}
+
+function cert_get_dates($str_crt, $decode = true) {
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+ $crt_details = openssl_x509_parse($str_crt);
+ if ($crt_details['validFrom_time_t'] > 0) {
+ $start = date('r', $crt_details['validFrom_time_t']);
+ }
+ if ($crt_details['validTo_time_t'] > 0) {
+ $end = date('r', $crt_details['validTo_time_t']);
+ }
+ return array($start, $end);
+}
+
+function cert_get_serial($str_crt, $decode = true) {
+ if ($decode) {
+ $str_crt = base64_decode($str_crt);
+ }
+ $crt_details = openssl_x509_parse($str_crt);
+ if (isset($crt_details['serialNumber']) && !empty($crt_details['serialNumber'])) {
+ return $crt_details['serialNumber'];
+ } else {
+ return NULL;
+ }
+}
+
+function prv_get_modulus($str_crt, $decode = true) {
+ return cert_get_modulus($str_crt, $decode, "prv");
+}
+
+function is_user_cert($certref) {
+ global $config;
+ if (!is_array($config['system']['user'])) {
+ return;
+ }
+ foreach ($config['system']['user'] as $user) {
+ if (!is_array($user['cert'])) {
+ continue;
+ }
+ foreach ($user['cert'] as $cert) {
+ if ($certref == $cert) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+function is_openvpn_server_cert($certref) {
+ global $config;
+ if (!is_array($config['openvpn']['openvpn-server'])) {
+ return;
+ }
+ foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
+ if ($ovpns['certref'] == $certref) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function is_openvpn_client_cert($certref) {
+ global $config;
+ if (!is_array($config['openvpn']['openvpn-client'])) {
+ return;
+ }
+ foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
+ if ($ovpnc['certref'] == $certref) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function is_ipsec_cert($certref) {
+ global $config;
+ if (!is_array($config['ipsec']['phase1'])) {
+ return;
+ }
+ foreach ($config['ipsec']['phase1'] as $ipsec) {
+ if ($ipsec['certref'] == $certref) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function is_webgui_cert($certref) {
+ global $config;
+ if (($config['system']['webgui']['ssl-certref'] == $certref) &&
+ ($config['system']['webgui']['protocol'] != "http")) {
+ return true;
+ }
+}
+
+function is_captiveportal_cert($certref) {
+ global $config;
+ if (!is_array($config['captiveportal'])) {
+ return;
+ }
+ foreach ($config['captiveportal'] as $portal) {
+ if (isset($portal['enable']) && isset($portal['httpslogin']) && ($portal['certref'] == $certref)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function cert_in_use($certref) {
+ return (is_webgui_cert($certref) ||
+ is_user_cert($certref) ||
+ is_openvpn_server_cert($certref) ||
+ is_openvpn_client_cert($certref) ||
+ is_ipsec_cert($certref) ||
+ is_captiveportal_cert($certref));
+}
+
+function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 9999) {
+ global $config;
+ $ca =& lookup_ca($caref);
+ if (!$ca) {
+ return false;
+ }
+ $crl['descr'] = $name;
+ $crl['caref'] = $caref;
+ $crl['serial'] = $serial;
+ $crl['lifetime'] = $lifetime;
+ $crl['cert'] = array();
+ $crl_res = crl_update($crl);
+ $config['crl'][] = $crl;
+ return $crl_res;
+}
+
+function crl_update(& $crl) {
+ global $config;
+ $ca =& lookup_ca($crl['caref']);
+ if (!$ca) {
+ return false;
+ }
+ // If we have text but no certs, it was imported and cannot be updated.
+ if (($crl["method"] != "internal") && (!empty($crl['text']) && empty($crl['cert']))) {
+ return false;
+ }
+ $crl['serial']++;
+ $ca_str_crt = base64_decode($ca['crt']);
+ $ca_str_key = base64_decode($ca['prv']);
+ $crl_res = openssl_crl_new($ca_str_crt, $crl['serial'], $crl['lifetime']);
+ if (is_array($crl['cert']) && (count($crl['cert']) > 0)) {
+ foreach ($crl['cert'] as $cert) {
+ openssl_crl_revoke_cert($crl_res, base64_decode($cert["crt"]), $cert["revoke_time"], $cert["reason"]);
+ }
+ }
+ openssl_crl_export($crl_res, $crl_text, $ca_str_key);
+ $crl['text'] = base64_encode($crl_text);
+ return $crl_res;
+}
+
+function cert_revoke($cert, & $crl, $reason = OCSP_REVOKED_STATUS_UNSPECIFIED) {
+ global $config;
+ if (is_cert_revoked($cert, $crl['refid'])) {
+ return true;
+ }
+ // If we have text but no certs, it was imported and cannot be updated.
+ if (!is_crl_internal($crl)) {
+ return false;
+ }
+ $cert["reason"] = $reason;
+ $cert["revoke_time"] = time();
+ $crl["cert"][] = $cert;
+ crl_update($crl);
+ return true;
+}
+
+function cert_unrevoke($cert, & $crl) {
+ global $config;
+ if (!is_crl_internal($crl)) {
+ return false;
+ }
+ foreach ($crl['cert'] as $id => $rcert) {
+ if (($rcert['refid'] == $cert['refid']) || ($rcert['descr'] == $cert['descr'])) {
+ unset($crl['cert'][$id]);
+ if (count($crl['cert']) == 0) {
+ // Protect against accidentally switching the type to imported, for older CRLs
+ if (!isset($crl['method'])) {
+ $crl['method'] = "internal";
+ }
+ crl_update($crl);
+ } else {
+ crl_update($crl);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Compare two certificates to see if they match. */
+function cert_compare($cert1, $cert2) {
+ /* Ensure two certs are identical by first checking that their issuers match, then
+ subjects, then serial numbers, and finally the moduli. Anything less strict
+ could accidentally count two similar, but different, certificates as
+ being identical. */
+ $c1 = base64_decode($cert1['crt']);
+ $c2 = base64_decode($cert2['crt']);
+ if ((cert_get_issuer($c1, false) == cert_get_issuer($c2, false)) &&
+ (cert_get_subject($c1, false) == cert_get_subject($c2, false)) &&
+ (cert_get_serial($c1, false) == cert_get_serial($c2, false)) &&
+ (cert_get_modulus($c1, false) == cert_get_modulus($c2, false))) {
+ return true;
+ }
+ return false;
+}
+
+function is_cert_revoked($cert, $crlref = "") {
+ global $config;
+ if (!is_array($config['crl'])) {
+ return false;
+ }
+
+ if (!empty($crlref)) {
+ $crl = lookup_crl($crlref);
+ if (!is_array($crl['cert'])) {
+ return false;
+ }
+ foreach ($crl['cert'] as $rcert) {
+ if (cert_compare($rcert, $cert)) {
+ return true;
+ }
+ }
+ } else {
+ foreach ($config['crl'] as $crl) {
+ if (!is_array($crl['cert'])) {
+ continue;
+ }
+ foreach ($crl['cert'] as $rcert) {
+ if (cert_compare($rcert, $cert)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+function is_openvpn_server_crl($crlref) {
+ global $config;
+ if (!is_array($config['openvpn']['openvpn-server'])) {
+ return;
+ }
+ foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
+ if (!empty($ovpns['crlref']) && ($ovpns['crlref'] == $crlref)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Keep this general to allow for future expansion. See cert_in_use() above.
+function crl_in_use($crlref) {
+ return (is_openvpn_server_crl($crlref));
+}
+
+function is_crl_internal($crl) {
+ return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["method"] == "internal"));
+}
+
+function cert_get_cn($crt, $isref = false) {
+ /* If this is a certref, not an actual cert, look up the cert first */
+ if ($isref) {
+ $cert = lookup_cert($crt);
+ /* If it's not a valid cert, bail. */
+ if (!(is_array($cert) && !empty($cert['crt']))) {
+ return "";
+ }
+ $cert = $cert['crt'];
+ } else {
+ $cert = $crt;
+ }
+ $sub = cert_get_subject_array($cert);
+ if (is_array($sub)) {
+ foreach ($sub as $s) {
+ if (strtoupper($s['a']) == "CN") {
+ return $s['v'];
+ }
+ }
+ }
+ return "";
+}
+
+?>
diff --git a/src/etc/inc/config.console.inc b/src/etc/inc/config.console.inc
new file mode 100644
index 0000000..df3fa6f
--- /dev/null
+++ b/src/etc/inc/config.console.inc
@@ -0,0 +1,560 @@
+<?php
+/****h* pfSense/config
+ * NAME
+ * config.inc - Functions to manipulate config.xml
+ * DESCRIPTION
+ * This include contains various config.xml specific functions.
+ * HISTORY
+ * $Id$
+ ******
+
+ config.console.inc
+ Copyright (C) 2004-2010 Scott Ullrich
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ pfSense_BUILDER_BINARIES: /sbin/mount /sbin/umount /sbin/halt /sbin/fsck
+ pfSense_MODULE: config
+*/
+
+function set_networking_interfaces_ports() {
+ global $noreboot;
+ global $config;
+ global $g;
+ global $fp;
+
+ $fp = fopen('php://stdin', 'r');
+
+ $memory = get_memory();
+ $physmem = $memory[0];
+ $realmem = $memory[1];
+
+ if ($physmem < $g['minimum_ram_warning']) {
+ echo "\n\n\n";
+ echo gettext("DANGER! WARNING! ACHTUNG!") . "\n\n";
+ printf(gettext("%s requires *AT LEAST* %s RAM to function correctly.%s"), $g['product_name'], $g['minimum_ram_warning_text'], "\n");
+ printf(gettext("Only (%s) MB RAM has been detected, with (%s) available to %s.%s"), $realmem, $physmem, $g['product_name'], "\n");
+ echo "\n" . gettext("Press ENTER to continue.") . " ";
+ fgets($fp);
+ echo "\n";
+ }
+
+ $iflist = get_interface_list();
+
+ /* Function flow is based on $key and $auto_assign or the lack thereof */
+ $key = null;
+
+ /* Only present auto interface option if running from LiveCD and interface mismatch*/
+ if ((preg_match("/cdrom/", $g['platform'])) && is_interface_mismatch()) {
+ $auto_assign = false;
+ }
+
+ echo <<<EOD
+
+Valid interfaces are:
+
+
+EOD;
+
+ if (!is_array($iflist)) {
+ echo gettext("No interfaces found!") . "\n";
+ $iflist = array();
+ } else {
+ foreach ($iflist as $iface => $ifa) {
+ echo sprintf("% -7s%s %s %s\n", $iface, $ifa['mac'],
+ $ifa['up'] ? " (up)" : "(down)", $ifa['dmesg']);
+ }
+ }
+
+ if ($auto_assign) {
+ echo <<<EOD
+
+ !!! LiveCD Detected: Auto Interface Option !!!!
+BEGIN MANUAL CONFIGURATION OR WE WILL PROCEED WITH AUTO CONFIGURATION.
+
+EOD;
+ }
+
+ echo <<<EOD
+
+Do you want to set up VLANs first?
+
+If you are not going to use VLANs, or only for optional interfaces, you should
+say no here and use the webConfigurator to configure VLANs later, if required.
+
+Do you want to set up VLANs now [y|n]?
+EOD;
+
+ if ($auto_assign) {
+ $key = timeout();
+ } else {
+ $key = chop(fgets($fp));
+ }
+
+ if (!isset($key) and $auto_assign) { // Auto Assign Interfaces
+ do {
+ echo <<<EOD
+
+ !!! Auto Assigning Interfaces !!!
+
+For installation purposes, you must plug in at least one NIC
+for the LAN connection. If you plug in a second NIC it will be
+assigned to WAN. Otherwise, we'll temporarily assign WAN to the
+next available NIC found regardless of activity. You should
+assign and configure the WAN interface according to your requirements
+
+If you haven't plugged in any network cables yet,
+now is the time to do so.
+We'll keep trying until you do.
+
+Searching for active interfaces...
+
+EOD;
+ unset($wanif, $lanif);
+
+ $media_iflist = $plugged_in = array();
+ $media_iflist = get_interface_list("media");
+ foreach ($media_iflist as $iface => $ifa) {
+ if ($ifa['up']) {
+ $plugged_in[] = $iface;
+ }
+ }
+
+ $lanif = array_shift($plugged_in);
+ $wanif = array_shift($plugged_in);
+
+ if (isset($lanif) && !isset($wanif)) {
+ foreach ($iflist as $iface => $ifa) {
+ if ($iface != $lanif) {
+ $wanif = $iface;
+ break;
+ }
+ }
+ }
+
+ echo <<<EOD
+
+Assigned WAN to : $wanif
+Assigned LAN to : $lanif
+
+If you don't like this assignment,
+press any key to go back to manual configuration.
+
+EOD;
+ $key = timeout(20);
+ if (isset($key)) {
+ return;
+ }
+ } while (!isset($wanif));
+
+ $config['system']['enablesshd'] = 'enabled';
+ $key = 'y';
+
+ } else {
+ //Manually assign interfaces
+ if (in_array($key, array('y', 'Y'))) {
+ vlan_setup();
+ }
+
+ if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
+
+ echo "\n\n" . gettext("VLAN interfaces:") . "\n\n";
+ foreach ($config['vlans']['vlan'] as $vlan) {
+
+ echo sprintf("% -16s%s\n", "{$vlan['if']}_vlan{$vlan['tag']}",
+ "VLAN tag {$vlan['tag']}, parent interface {$vlan['if']}");
+
+ $iflist[$vlan['if'] . '_vlan' . $vlan['tag']] = array();
+ }
+ }
+
+ echo <<<EOD
+
+If you do not know the names of your interfaces, you may choose to use
+auto-detection. In that case, disconnect all interfaces now before
+hitting 'a' to initiate auto detection.
+
+EOD;
+
+ do {
+ echo "\n" . gettext("Enter the WAN interface name or 'a' for auto-detection:") . " ";
+ $wanif = chop(fgets($fp));
+ if ($wanif === "") {
+ return;
+ }
+ if ($wanif === "a") {
+ $wanif = autodetect_interface("WAN", $fp);
+ } else if (!array_key_exists($wanif, $iflist)) {
+ printf(gettext("%sInvalid interface name '%s'%s"), "\n", $wanif, "\n");
+ unset($wanif);
+ continue;
+ }
+ } while (!$wanif);
+
+ do {
+ printf(gettext("%sEnter the LAN interface name or 'a' for auto-detection %s" .
+ "NOTE: this enables full Firewalling/NAT mode.%s" .
+ "(or nothing if finished):%s"), "\n", "\n", "\n", " ");
+
+ $lanif = chop(fgets($fp));
+
+ if ($lanif == "exit") {
+ exit;
+ }
+
+ if ($lanif == "") {
+ /* It is OK to have just a WAN, without a LAN so break if the user does not want LAN. */
+ break;
+ }
+
+ if ($lanif === "a") {
+ $lanif = autodetect_interface("LAN", $fp);
+ } else if (!array_key_exists($lanif, $iflist)) {
+ printf(gettext("%sInvalid interface name '%s'%s"), "\n", $lanif, "\n");
+ unset($lanif);
+ continue;
+ }
+ } while (!$lanif);
+
+ /* optional interfaces */
+ $i = 0;
+ $optif = array();
+
+ if ($lanif <> "") {
+ while (1) {
+ if ($optif[$i]) {
+ $i++;
+ }
+ $io = $i + 1;
+
+ if ($config['interfaces']['opt' . $io]['descr']) {
+ printf(gettext("%sOptional interface %s description found: %s"), "\n", $io, $config['interfaces']['opt' . $io]['descr']);
+ }
+
+ printf(gettext("%sEnter the Optional %s interface name or 'a' for auto-detection%s" .
+ "(or nothing if finished):%s"), "\n", $io, "\n", " ");
+
+ $optif[$i] = chop(fgets($fp));
+
+ if ($optif[$i]) {
+ if ($optif[$i] === "a") {
+ $ad = autodetect_interface(gettext("Optional") . " " . $io, $fp);
+ if ($ad) {
+ $optif[$i] = $ad;
+ } else {
+ unset($optif[$i]);
+ }
+ } else if (!array_key_exists($optif[$i], $iflist)) {
+ printf(gettext("%sInvalid interface name '%s'%s"), "\n", $optif[$i], "\n");
+ unset($optif[$i]);
+ continue;
+ }
+ } else {
+ unset($optif[$i]);
+ break;
+ }
+ }
+ }
+
+ /* check for double assignments */
+ $ifarr = array_merge(array($lanif, $wanif), $optif);
+
+ for ($i = 0; $i < (count($ifarr)-1); $i++) {
+ for ($j = ($i+1); $j < count($ifarr); $j++) {
+ if ($ifarr[$i] == $ifarr[$j]) {
+ echo <<<EOD
+
+Error: you cannot assign the same interface name twice!
+
+EOD;
+ fclose($fp);
+ return;
+ }
+ }
+ }
+
+ echo "\n" . gettext("The interfaces will be assigned as follows:") . "\n\n";
+
+ echo "WAN -> " . $wanif . "\n";
+ if ($lanif != "") {
+ echo "LAN -> " . $lanif . "\n";
+ }
+ for ($i = 0; $i < count($optif); $i++) {
+ echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
+ }
+
+ echo <<<EOD
+
+Do you want to proceed [y|n]?
+EOD;
+ $key = chop(fgets($fp));
+ }
+
+ if (in_array($key, array('y', 'Y'))) {
+ if ($lanif) {
+ if (!is_array($config['interfaces']['lan'])) {
+ $config['interfaces']['lan'] = array();
+ }
+ $config['interfaces']['lan']['if'] = $lanif;
+ $config['interfaces']['lan']['enable'] = true;
+ } elseif (!platform_booting() && !$auto_assign) {
+
+echo <<<EODD
+
+You have chosen to remove the LAN interface.
+
+Would you like to remove the LAN IP address and
+unload the interface now? [y|n]?
+EODD;
+
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+ if (isset($config['interfaces']['lan']) && $config['interfaces']['lan']['if']) {
+ mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
+ }
+ }
+ if (isset($config['interfaces']['lan'])) {
+ unset($config['interfaces']['lan']);
+ }
+ if (isset($config['dhcpd']['lan'])) {
+ unset($config['dhcpd']['lan']);
+ }
+ if (isset($config['interfaces']['lan']['if'])) {
+ unset($config['interfaces']['lan']['if']);
+ }
+ if (isset($config['interfaces']['wan']['blockpriv'])) {
+ unset($config['interfaces']['wan']['blockpriv']);
+ }
+ if (isset($config['shaper'])) {
+ unset($config['shaper']);
+ }
+ if (isset($config['ezshaper'])) {
+ unset($config['ezshaper']);
+ }
+ if (isset($config['nat'])) {
+ unset($config['nat']);
+ }
+ } else {
+ if (isset($config['interfaces']['lan']['if'])) {
+ mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
+ }
+ if (isset($config['interfaces']['lan'])) {
+ unset($config['interfaces']['lan']);
+ }
+ if (isset($config['dhcpd']['lan'])) {
+ unset($config['dhcpd']['lan']);
+ }
+ if (isset($config['interfaces']['lan']['if'])) {
+ unset($config['interfaces']['lan']['if']);
+ }
+ if (isset($config['interfaces']['wan']['blockpriv'])) {
+ unset($config['interfaces']['wan']['blockpriv']);
+ }
+ if (isset($config['shaper'])) {
+ unset($config['shaper']);
+ }
+ if (isset($config['ezshaper'])) {
+ unset($config['ezshaper']);
+ }
+ if (isset($config['nat'])) {
+ unset($config['nat']);
+ }
+ }
+ if (preg_match($g['wireless_regex'], $lanif)) {
+ if (is_array($config['interfaces']['lan']) &&
+ !is_array($config['interfaces']['lan']['wireless'])) {
+ $config['interfaces']['lan']['wireless'] = array();
+ }
+ } else {
+ if (isset($config['interfaces']['lan'])) {
+ unset($config['interfaces']['lan']['wireless']);
+ }
+ }
+
+ if (!is_array($config['interfaces']['wan'])) {
+ $config['interfaces']['wan'] = array();
+ }
+ $config['interfaces']['wan']['if'] = $wanif;
+ $config['interfaces']['wan']['enable'] = true;
+ if (preg_match($g['wireless_regex'], $wanif)) {
+ if (is_array($config['interfaces']['wan']) &&
+ !is_array($config['interfaces']['wan']['wireless'])) {
+ $config['interfaces']['wan']['wireless'] = array();
+ }
+ } else {
+ if (isset($config['interfaces']['wan'])) {
+ unset($config['interfaces']['wan']['wireless']);
+ }
+ }
+
+ for ($i = 0; $i < count($optif); $i++) {
+ if (!is_array($config['interfaces']['opt' . ($i+1)])) {
+ $config['interfaces']['opt' . ($i+1)] = array();
+ }
+
+ $config['interfaces']['opt' . ($i+1)]['if'] = $optif[$i];
+
+ /* wireless interface? */
+ if (preg_match($g['wireless_regex'], $optif[$i])) {
+ if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless'])) {
+ $config['interfaces']['opt' . ($i+1)]['wireless'] = array();
+ }
+ } else {
+ unset($config['interfaces']['opt' . ($i+1)]['wireless']);
+ }
+
+ if (empty($config['interfaces']['opt' . ($i+1)]['descr'])) {
+ $config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
+ unset($config['interfaces']['opt' . ($i+1)]['enable']);
+ }
+ }
+
+ /* remove all other (old) optional interfaces */
+ for (; isset($config['interfaces']['opt' . ($i+1)]); $i++) {
+ unset($config['interfaces']['opt' . ($i+1)]);
+ }
+
+ printf(gettext("%sWriting configuration..."), "\n");
+ write_config("Console assignment of interfaces");
+ printf(gettext("done.%s"), "\n");
+
+ fclose($fp);
+
+ if (platform_booting()) {
+ return;
+ }
+
+ echo gettext("One moment while we reload the settings...");
+ echo gettext(" done!") . "\n";
+
+ touch("{$g['tmp_path']}/assign_complete");
+
+ }
+}
+
+function autodetect_interface($ifname, $fp) {
+ $iflist_prev = get_interface_list("media");
+ echo <<<EOD
+
+Connect the {$ifname} interface now and make sure that the link is up.
+Then press ENTER to continue.
+
+EOD;
+ fgets($fp);
+ $iflist = get_interface_list("media");
+
+ foreach ($iflist_prev as $ifn => $ifa) {
+ if (!$ifa['up'] && $iflist[$ifn]['up']) {
+ printf(gettext("Detected link-up on interface %s.%s"), $ifn, "\n");
+ return $ifn;
+ }
+ }
+
+ printf(gettext("No link-up detected.%s"), "\n");
+
+ return null;
+}
+
+function interfaces_setup() {
+ global $iflist, $config, $g, $fp;
+
+ $iflist = get_interface_list();
+}
+
+function vlan_setup() {
+ global $iflist, $config, $g, $fp;
+
+ $iflist = get_interface_list();
+
+ if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
+
+ echo <<<EOD
+
+WARNING: all existing VLANs will be cleared if you proceed!
+
+Do you want to proceed [y|n]?
+EOD;
+
+ if (strcasecmp(chop(fgets($fp)), "y") != 0) {
+ return;
+ }
+ }
+
+ $config['vlans']['vlan'] = array();
+ echo "\n";
+
+ $vlanif = 0;
+
+ while (1) {
+ $vlan = array();
+
+ echo "\n\n" . gettext("VLAN Capable interfaces:") . "\n\n";
+ if (!is_array($iflist)) {
+ echo gettext("No interfaces found!") . "\n";
+ } else {
+ $vlan_capable = 0;
+ foreach ($iflist as $iface => $ifa) {
+ if (is_jumbo_capable($iface)) {
+ echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
+ $ifa['up'] ? " (up)" : "");
+ $vlan_capable++;
+ }
+ }
+ }
+
+ if ($vlan_capable == 0) {
+ echo gettext("No VLAN capable interfaces detected.") . "\n";
+ return;
+ }
+
+ echo "\n" . gettext("Enter the parent interface name for the new VLAN (or nothing if finished):") . " ";
+ $vlan['if'] = chop(fgets($fp));
+
+ if ($vlan['if']) {
+ if (!array_key_exists($vlan['if'], $iflist) or
+ !is_jumbo_capable($vlan['if'])) {
+ printf(gettext("%sInvalid interface name '%s'%s"), "\n", $vlan['if'], "\n");
+ continue;
+ }
+ } else {
+ break;
+ }
+
+ echo gettext("Enter the VLAN tag (1-4094):") . " ";
+ $vlan['tag'] = chop(fgets($fp));
+ $vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
+ if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
+ printf(gettext("%sInvalid VLAN tag '%s'%s"), "\n", $vlan['tag'], "\n");
+ continue;
+ }
+
+ $config['vlans']['vlan'][] = $vlan;
+ $vlanif++;
+ }
+}
+
+?>
diff --git a/src/etc/inc/config.gui.inc b/src/etc/inc/config.gui.inc
new file mode 100644
index 0000000..56b5555
--- /dev/null
+++ b/src/etc/inc/config.gui.inc
@@ -0,0 +1,96 @@
+<?php
+/****h* pfSense/config
+ * NAME
+ * config.gui.inc - Functions to manipulate config.xml
+ * DESCRIPTION
+ * This include contains various config.xml specific functions.
+ * HISTORY
+ * $Id$
+ ******
+
+ config.gui.inc
+ Copyright (C) 2004-2010 Scott Ullrich
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ pfSense_BUILDER_BINARIES: /sbin/mount /sbin/umount /sbin/halt /sbin/fsck
+ pfSense_MODULE: config
+*/
+
+require_once("globals.inc");
+
+/* do not load this file twice. */
+if ($config_parsed == true) {
+ return;
+} else {
+ $config_parsed = true;
+}
+
+/* include globals from notices.inc /utility/XML parser files */
+require_once('config.lib.inc');
+require_once("notices.inc");
+require_once("util.inc");
+require_once("IPv6.inc");
+if (file_exists("/cf/conf/use_xmlreader")) {
+ require_once("xmlreader.inc");
+} else {
+ require_once("xmlparse.inc");
+}
+require_once("crypt.inc");
+
+/* read platform */
+if (file_exists("{$g['etc_path']}/platform")) {
+ $g['platform'] = chop(file_get_contents("{$g['etc_path']}/platform"));
+} else {
+ $g['platform'] = "unknown";
+}
+
+/* if /debugging exists, lets set $debugging
+ so we can output more information */
+if (file_exists("/debugging")) {
+ $debugging = true;
+ $g['debug'] = true;
+}
+
+$config = parse_config();
+
+/* set timezone */
+$timezone = $config['system']['timezone'];
+if (!$timezone) {
+ $timezone = "Etc/UTC";
+}
+date_default_timezone_set("$timezone");
+
+if ($config_parsed == true) {
+ /* process packager manager custom rules */
+ if (is_dir("/usr/local/pkg/parse_config")) {
+ run_plugins("/usr/local/pkg/parse_config/");
+ }
+}
+
+?>
diff --git a/src/etc/inc/config.inc b/src/etc/inc/config.inc
new file mode 100644
index 0000000..4792ac3
--- /dev/null
+++ b/src/etc/inc/config.inc
@@ -0,0 +1,226 @@
+<?php
+/****h* pfSense/config
+ * NAME
+ * config.inc - Functions to manipulate config.xml
+ * DESCRIPTION
+ * This include contains various config.xml specific functions.
+ * HISTORY
+ * $Id$
+ ******
+
+ config.inc
+ Copyright (C) 2004-2010 Scott Ullrich
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ pfSense_BUILDER_BINARIES: /sbin/mount /sbin/umount /sbin/halt /sbin/fsck
+ pfSense_MODULE: config
+*/
+
+if (!function_exists('platform_booting')) {
+ require_once('globals.inc');
+}
+
+/* do not load this file twice. */
+//if (in_array("/etc/inc/config.inc", get_included_files()))
+// return;
+
+// Set the memory limit to 128M on i386. When someone has something like 500+ tunnels
+// the parser needs quite a bit of ram. Do not remove this line unless you
+// know what you are doing. If in doubt, check with dev@ _/FIRST/_!
+if (!$ARCH) {
+ $ARCH = php_uname("m");
+}
+
+// Set memory limit to 256M on amd64.
+if ($ARCH == "amd64") {
+ ini_set("memory_limit", "256M");
+} else {
+ ini_set("memory_limit", "128M");
+}
+
+/* include globals from notices.inc /utility/XML parser files */
+require_once("notices.inc");
+require_once("util.inc");
+require_once("IPv6.inc");
+require_once('config.lib.inc');
+if (file_exists("/cf/conf/use_xmlreader")) {
+ require_once("xmlreader.inc");
+} else {
+ require_once("xmlparse.inc");
+}
+require_once("crypt.inc");
+
+/* read platform */
+if (file_exists("{$g['etc_path']}/platform")) {
+ $g['platform'] = chop(file_get_contents("{$g['etc_path']}/platform"));
+} else {
+ $g['platform'] = "unknown";
+}
+
+/* if /debugging exists, lets set $debugging
+ so we can output more information */
+if (file_exists("/debugging")) {
+ $debugging = true;
+ $g['debug'] = true;
+}
+
+if (platform_booting(true)) {
+ echo ".";
+ if (file_exists("/cf/conf/config.xml")) {
+ $config_contents = file_get_contents("/cf/conf/config.xml");
+ if (stristr($config_contents, "<m0n0wall>") == true) {
+ echo ".";
+ /* user has just upgraded from m0n0wall, replace root xml tags */
+ log_error(gettext("Upgrading m0n0wall configuration to pfSense... "));
+ $config_contents = str_replace("m0n0wall", "pfsense", $config_contents);
+ if (!config_validate("{$g['conf_path']}/config.xml")) {
+ log_error(gettext("ERROR! Could not convert m0n0wall -> pfsense in config.xml"));
+ }
+ conf_mount_rw();
+ file_put_contents("/cf/conf/config.xml", $config_contents);
+ conf_mount_ro();
+ }
+ unset($config_contents);
+ }
+ /* if our config file exists bail out, we're already set. */
+ else if (!file_exists($g['cf_conf_path'] . "/config.xml")) {
+ echo ".";
+ /* find the device where config.xml resides and write out an fstab */
+ unset($cfgdevice);
+ echo ".";
+ /* check if there's already an fstab (NFS booting?) */
+ if (!file_exists("{$g['etc_path']}/fstab")) {
+ echo ".";
+ if (strstr($g['platform'], "cdrom")) {
+ /* config is on floppy disk for CD-ROM version */
+ $cfgdevice = $cfgpartition = "fd0";
+ $_gb = exec('/sbin/dmesg -a', $dmesg);
+ if (preg_match("/da0/", $dmesg) == true) {
+ $cfgdevice = $cfgpartition = "da0" ;
+ if (mwexec("/sbin/mount -r /dev/{$cfgdevice} /cf")) {
+ /* could not mount, fallback to floppy */
+ $cfgdevice = $cfgpartition = "fd0";
+ }
+ }
+ unset($dmesg);
+ $cfgfstype = "msdosfs";
+ echo gettext("CDROM build") . "\n";
+ echo " " . gettext("CFG:") . " {$cfgpartition}\n";
+ echo " " . gettext("CFG:") . " {$cfgpartition}\n";
+ echo " " . gettext("TYPE:") . " {$cfgfstype}\n";
+ } else {
+ echo ".";
+ /* probe kernel known disks until we find one with config.xml */
+ $disks = explode(" ", get_single_sysctl("kern.disks"));
+ foreach ($disks as $mountdisk) {
+ /* skip mfs mounted filesystems */
+ if (strstr($mountdisk, "md")) {
+ continue;
+ }
+ if (mwexec("/sbin/mount -r /dev/{$mountdisk}a {$g['cf_path']}") == 0) {
+ if (file_exists("{$g['cf_conf_path']}/config.xml")) {
+ /* found it */
+ $cfgdevice = $mountdisk;
+ $cfgpartition = $cfgdevice . "a";
+ $cfgfstype = "ufs";
+ printf(gettext("Found configuration on %s.%s"), $cfgdevice, "\n");
+ }
+
+ mwexec("/sbin/umount -f {$g['cf_path']}");
+
+ if ($cfgdevice) {
+ break;
+ }
+ }
+ if (mwexec("/sbin/mount -r /dev/{$mountdisk}d {$g['cf_path']}") == 0) {
+ if (platform_booting()) {
+ echo ".";
+ }
+ if (file_exists("{$g['cf_conf_path']}/config.xml")) {
+ /* found it */
+ $cfgdevice = $mountdisk;
+ $cfgpartition = $cfgdevice . "d";
+ $cfgfstype = "ufs";
+ printf(gettext("Found configuration on %s.%s"), $cfgdevice, "\n");
+ }
+
+ mwexec("/sbin/umount -f {$g['cf_path']}");
+
+ if ($cfgdevice) {
+ break;
+ }
+ }
+ }
+ }
+ echo ".";
+ if (!$cfgdevice) {
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ log_error(gettext("No config.xml found, attempting last known config restore."));
+ file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
+ restore_backup("/cf/conf/backup/{$last_backup}");
+ } else {
+ log_error(gettext("No config.xml or config backups found, resetting to factory defaults."));
+ restore_backup('/conf.default/config.xml');
+ }
+ }
+
+ /* write device name to a file for rc.firmware */
+ file_put_contents("{$g['varetc_path']}/cfdevice", $cfgdevice . "\n");
+
+ /* write out an fstab */
+
+ $fstab = "/dev/{$cfgpartition} {$g['cf_path']} {$cfgfstype} ro,noatime 1 1\n";
+ $fstab .= "proc /proc procfs rw 0 0\n";
+ file_put_contents("{$g['etc_path']}/fstab", $fstab);
+ }
+ echo ".";
+ /* mount all filesystems */
+ mwexec("/sbin/mount -a");
+ }
+ echo ".";
+}
+
+$config = parse_config();
+
+/* set timezone */
+$timezone = $config['system']['timezone'];
+if (!$timezone) {
+ $timezone = "Etc/UTC";
+}
+date_default_timezone_set("$timezone");
+
+if ($config_parsed == true) {
+ /* process packager manager custom rules */
+ if (is_dir("/usr/local/pkg/parse_config")) {
+ run_plugins("/usr/local/pkg/parse_config/");
+ }
+}
+
+?>
diff --git a/src/etc/inc/config.lib.inc b/src/etc/inc/config.lib.inc
new file mode 100644
index 0000000..222d9d8
--- /dev/null
+++ b/src/etc/inc/config.lib.inc
@@ -0,0 +1,1020 @@
+<?php
+/****h* pfSense/config
+ * NAME
+ * config.lib.inc - Functions to manipulate config.xml
+ * DESCRIPTION
+ * This include contains various config.xml specific functions.
+ * HISTORY
+ * $Id$
+ ******
+
+ config.lib.inc
+ Ported from config.inc by Erik Kristensen
+ Copyright (C) 2004-2010 Scott Ullrich
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ pfSense_BUILDER_BINARIES: /sbin/mount /sbin/umount /sbin/halt
+ pfSense_MODULE: config
+*/
+
+/****f* config/encrypted_configxml
+ * NAME
+ * encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
+ * INPUTS
+ * None
+ * RESULT
+ * $config - rewrites config.xml without encryption
+ ******/
+function encrypted_configxml() {
+ global $g, $config;
+
+ if (!file_exists($g['conf_path'] . "/config.xml")) {
+ return;
+ }
+
+ if (!platform_booting()) {
+ return;
+ }
+
+ $configtxt = file_get_contents($g['conf_path'] . "/config.xml");
+ if (tagfile_deformat($configtxt, $configtxt, "config.xml")) {
+ $fp = fopen('php://stdin', 'r');
+ $data = "";
+ echo "\n\n*** Encrypted config.xml detected ***\n";
+ while ($data == "") {
+ echo "\nEnter the password to decrypt config.xml: ";
+ $decrypt_password = chop(fgets($fp));
+ $data = decrypt_data($configtxt, $decrypt_password);
+ if (!strstr($data, "<pfsense>")) {
+ $data = "";
+ }
+ if ($data) {
+ $fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
+ fwrite($fd, $data);
+ fclose($fd);
+ exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
+ echo "\n" . gettext("Config.xml unlocked.") . "\n";
+ fclose($fp);
+ pfSense_fsync("{$g['conf_path']}/config.xml");
+ } else {
+ echo "\n" . gettext("Invalid password entered. Please try again.") . "\n";
+ }
+ }
+ }
+}
+
+/****f* config/parse_config
+ * NAME
+ * parse_config - Read in config.cache or config.xml if needed and return $config array
+ * INPUTS
+ * $parse - boolean to force parse_config() to read config.xml and generate config.cache
+ * RESULT
+ * $config - array containing all configuration variables
+ ******/
+function parse_config($parse = false) {
+ global $g, $config_parsed, $config_extra;
+
+ $lockkey = lock('config');
+ $config_parsed = false;
+
+ if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ log_error(gettext("No config.xml found, attempting last known config restore."));
+ file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
+ restore_backup("{$g['conf_path']}/backup/{$last_backup}");
+ } else {
+ unlock($lockkey);
+ die(gettext("Config.xml is corrupted and is 0 bytes. Could not restore a previous backup."));
+ }
+ }
+
+ if (platform_booting(true)) {
+ echo ".";
+ }
+
+ // Check for encrypted config.xml
+ encrypted_configxml();
+
+ if (!$parse) {
+ if (file_exists($g['tmp_path'] . '/config.cache')) {
+ $config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
+ if (is_null($config)) {
+ $parse = true;
+ }
+ } else {
+ $parse = true;
+ }
+ }
+ if ($parse == true) {
+ if (!file_exists($g['conf_path'] . "/config.xml")) {
+ if (platform_booting(true)) {
+ echo ".";
+ }
+ log_error("No config.xml found, attempting last known config restore.");
+ file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ restore_backup("/cf/conf/backup/{$last_backup}");
+ } else {
+ log_error(gettext("Could not restore config.xml."));
+ unlock($lockkey);
+ die(gettext("Config.xml is corrupted and is 0 bytes. Could not restore a previous backup."));
+ }
+ }
+ $config = parse_xml_config($g['conf_path'] . '/config.xml', array($g['xml_rootobj'], 'pfsense'));
+ if ($config == -1) {
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ restore_backup("/cf/conf/backup/{$last_backup}");
+ } else {
+ log_error(gettext("Could not restore config.xml."));
+ unlock($lockkey);
+ die("Config.xml is corrupted and is 0 bytes. Could not restore a previous backup.");
+ }
+ }
+ generate_config_cache($config);
+ }
+
+ if (platform_booting(true)) {
+ echo ".";
+ }
+
+ $config_parsed = true;
+ unlock($lockkey);
+
+ alias_make_table($config);
+
+ return $config;
+}
+
+/****f* config/generate_config_cache
+ * NAME
+ * generate_config_cache - Write serialized configuration to cache.
+ * INPUTS
+ * $config - array containing current firewall configuration
+ * RESULT
+ * boolean - true on completion
+ ******/
+function generate_config_cache($config) {
+ global $g, $config_extra;
+
+ $configcache = fopen($g['tmp_path'] . '/config.cache', "w");
+ fwrite($configcache, serialize($config));
+ fclose($configcache);
+ pfSense_fsync("{$g['tmp_path']}/config.cache");
+
+ unset($configcache);
+ /* Used for config.extra.xml */
+ if (file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
+ $configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
+ fwrite($configcacheextra, serialize($config_extra));
+ fclose($configcacheextra);
+ pfSense_fsync("{$g['tmp_path']}/config.extra.cache");
+ unset($configcacheextra);
+ }
+}
+
+function discover_last_backup() {
+ $backups = glob('/cf/conf/backup/*.xml');
+ $last_backup = "";
+ $last_mtime = 0;
+ foreach ($backups as $backup) {
+ if (filemtime($backup) > $last_mtime) {
+ $last_mtime = filemtime($backup);
+ $last_backup = $backup;
+ }
+ }
+
+ return basename($last_backup);
+}
+
+function restore_backup($file) {
+ global $g;
+
+ if (file_exists($file)) {
+ conf_mount_rw();
+ unlink_if_exists("{$g['tmp_path']}/config.cache");
+ copy("$file", "/cf/conf/config.xml");
+ pfSense_fsync("/cf/conf/config.xml");
+ pfSense_fsync($g['conf_path']);
+ disable_security_checks();
+ log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
+ file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
+ conf_mount_ro();
+ }
+}
+
+/****f* config/parse_config_bootup
+ * NAME
+ * parse_config_bootup - Bootup-specific configuration checks.
+ * RESULT
+ * null
+ ******/
+function parse_config_bootup() {
+ global $config, $g;
+
+ if (platform_booting()) {
+ echo ".";
+ }
+
+ $lockkey = lock('config');
+ if (!file_exists("{$g['conf_path']}/config.xml")) {
+ if (platform_booting()) {
+ if (strstr($g['platform'], "cdrom")) {
+ /* try copying the default config. to the floppy */
+ echo gettext("Resetting factory defaults...") . "\n";
+ reset_factory_defaults(true);
+ if (!file_exists("{$g['conf_path']}/config.xml")) {
+ echo gettext("No XML configuration file found - using factory defaults.\n" .
+ "Make sure that the configuration floppy disk with the conf/config.xml\n" .
+ "file is inserted. If it isn't, your configuration changes will be lost\n" .
+ "on reboot.\n");
+ }
+ } else {
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ log_error("No config.xml found, attempting last known config restore.");
+ file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
+ restore_backup("/cf/conf/backup/{$last_backup}");
+ }
+ if (!file_exists("{$g['conf_path']}/config.xml")) {
+ echo sprintf(gettext("XML configuration file not found. %s cannot continue booting."), $g['product_name']) . "\n";
+ unlock($lockkey);
+ mwexec("/sbin/halt");
+ exit;
+ }
+ log_error("Last known config found and restored. Please double check your configuration file for accuracy.");
+ file_notice("config.xml", gettext("Last known config found and restored. Please double check your configuration file for accuracy."), "pfSenseConfigurator", "");
+ }
+ } else {
+ unlock($lockkey);
+ log_error(gettext("Could not find a usable configuration file! Exiting...."));
+ exit(0);
+ }
+ }
+
+ if (filesize("{$g['conf_path']}/config.xml") == 0) {
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ log_error(gettext("No config.xml found, attempting last known config restore."));
+ file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
+ restore_backup("{$g['conf_path']}/backup/{$last_backup}");
+ } else {
+ unlock($lockkey);
+ die(gettext("Config.xml is corrupted and is 0 bytes. Could not restore a previous backup."));
+ }
+ }
+ unlock($lockkey);
+
+ $config = parse_config(true);
+
+ if ((float)$config['version'] > (float)$g['latest_config']) {
+ echo <<<EOD
+
+
+*******************************************************************************
+* WARNING! *
+* The current configuration has been created with a newer version of {$g['product_name']} *
+* than this one! This can lead to serious misbehavior and even security *
+* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or *
+* revert to the default configuration immediately! *
+*******************************************************************************
+
+
+EOD;
+ }
+
+ /* make alias table (for faster lookups) */
+ alias_make_table($config);
+}
+
+/****f* config/conf_mount_rw
+ * NAME
+ * conf_mount_rw - Mount filesystems read/write.
+ * RESULT
+ * null
+ ******/
+/* mount flash card read/write */
+function conf_mount_rw() {
+ global $g, $config;
+
+ /* do not mount on cdrom platform */
+ if ($g['platform'] == "cdrom" or $g['platform'] == "pfSense") {
+ return;
+ }
+
+ if ((refcount_reference(1000) > 1) && is_writable("/")) {
+ return;
+ }
+
+ $status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
+ if ($status <> 0) {
+ if (platform_booting()) {
+ echo gettext("/cf Filesystem is dirty.") . "\n";
+ }
+ $status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
+ }
+
+ /* if the platform is soekris or wrap or pfSense, lets mount the
+ * compact flash cards root.
+ */
+ $status = mwexec("/sbin/mount -u -w -o sync,noatime /");
+ /* we could not mount this correctly. */
+ if ($status <> 0) {
+ log_error(gettext("/ File system is dirty."));
+ $status = mwexec("/sbin/mount -u -w -o sync,noatime /");
+ }
+
+ mark_subsystem_dirty('mount');
+}
+
+/****f* config/conf_mount_ro
+ * NAME
+ * conf_mount_ro - Mount filesystems readonly.
+ * RESULT
+ * null
+ ******/
+function conf_mount_ro() {
+ global $g, $config;
+
+ /* Do not trust $g['platform'] since this can be clobbered during factory reset. */
+ $platform = trim(file_get_contents("/etc/platform"));
+ /* do not umount on cdrom or pfSense platforms */
+ if ($platform == "cdrom" or $platform == "pfSense") {
+ return;
+ }
+
+ if (refcount_unreference(1000) > 0) {
+ return;
+ }
+
+ if (isset($config['system']['nanobsd_force_rw'])) {
+ return;
+ }
+
+ if (platform_booting()) {
+ return;
+ }
+
+ clear_subsystem_dirty('mount');
+ /* sync data, then force a remount of /cf */
+ pfSense_fsync($g['cf_path']);
+ mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
+ mwexec("/sbin/mount -u -r -f -o sync,noatime /");
+}
+
+/****f* config/convert_config
+ * NAME
+ * convert_config - Attempt to update config.xml.
+ * DESCRIPTION
+ * convert_config() reads the current global configuration
+ * and attempts to convert it to conform to the latest
+ * config.xml version. This allows major formatting changes
+ * to be made with a minimum of breakage.
+ * RESULT
+ * null
+ ******/
+/* convert configuration, if necessary */
+function convert_config() {
+ global $config, $g;
+ $now = date("H:i:s");
+ log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
+ //ini_set("max_execution_time", "900");
+
+ /* special case upgrades */
+ /* fix every minute crontab bogons entry */
+ if (is_array($config['cron'])) {
+ $cron_item_count = count($config['cron']['item']);
+ for ($x = 0; $x < $cron_item_count; $x++) {
+ if (stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
+ if ($config['cron']['item'][$x]['hour'] == "*") {
+ $config['cron']['item'][$x]['hour'] = "3";
+ write_config(gettext("Updated bogon update frequency to 3am"));
+ log_error(gettext("Updated bogon update frequency to 3am"));
+ }
+ }
+ }
+ }
+ if ($config['version'] == $g['latest_config']) {
+ return; /* already at latest version */
+ }
+
+ // Save off config version
+ $prev_version = $config['version'];
+
+ include_once('auth.inc');
+ include_once('upgrade_config.inc');
+ if (file_exists("/etc/inc/upgrade_config_custom.inc")) {
+ include_once("upgrade_config_custom.inc");
+ }
+ /* Loop and run upgrade_VER_to_VER() until we're at current version */
+ while ($config['version'] < $g['latest_config']) {
+ $cur = $config['version'] * 10;
+ $next = $cur + 1;
+ $migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
+ if (function_exists($migration_function)) {
+ $migration_function();
+ }
+ $migration_function = "{$migration_function}_custom";
+ if (function_exists($migration_function)) {
+ $migration_function();
+ }
+ $config['version'] = sprintf('%.1f', $next / 10);
+ if (platform_booting()) {
+ echo ".";
+ }
+ }
+
+ $now = date("H:i:s");
+ log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
+
+ if ($prev_version != $config['version']) {
+ write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
+ }
+}
+
+/****f* config/safe_write_file
+ * NAME
+ * safe_write_file - Write a file out atomically
+ * DESCRIPTION
+ * safe_write_file() Writes a file out atomically by first writing to a
+ * temporary file of the same name but ending with the pid of the current
+ * process, them renaming the temporary file over the original.
+ * INPUTS
+ * $filename - string containing the filename of the file to write
+ * $content - string containing the file content to write to file
+ * $force_binary - boolean denoting whether we should force binary
+ * mode writing.
+ * RESULT
+ * boolean - true if successful, false if not
+ ******/
+function safe_write_file($file, $content, $force_binary) {
+ $tmp_file = $file . "." . getmypid();
+ $write_mode = $force_binary ? "wb" : "w";
+
+ $fd = fopen($tmp_file, $write_mode);
+ if (!$fd) {
+ // Unable to open temporary file for writing
+ return false;
+ }
+ if (!fwrite($fd, $content)) {
+ // Unable to write to temporary file
+ fclose($fd);
+ return false;
+ }
+ fflush($fd);
+ fclose($fd);
+
+ if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
+ // Unable to move temporary file to original
+ @unlink($tmp_file);
+ return false;
+ }
+
+ // Sync file before returning
+ return pfSense_fsync($file);
+}
+
+/****f* config/write_config
+ * NAME
+ * write_config - Backup and write the firewall configuration.
+ * DESCRIPTION
+ * write_config() handles backing up the current configuration,
+ * applying changes, and regenerating the configuration cache.
+ * INPUTS
+ * $desc - string containing the a description of configuration changes
+ * $backup - boolean: do not back up current configuration if false.
+ * RESULT
+ * null
+ ******/
+/* save the system configuration */
+function write_config($desc="Unknown", $backup = true) {
+ global $config, $g;
+
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
+ if (!session_id()) {
+ @session_start();
+ }
+ if (!empty($_SESSION['Username']) && ($_SESSION['Username'] != "admin")) {
+ $user = getUserEntry($_SESSION['Username']);
+ if (is_array($user) && userHasPrivilege($user, "user-config-readonly")) {
+ session_commit();
+ return false;
+ }
+ }
+ }
+
+ if (!isset($argc)) {
+ session_commit();
+ }
+
+ if ($backup) {
+ backup_config();
+ }
+
+ $config['revision'] = make_config_revision_entry($desc);
+
+ conf_mount_rw();
+ $lockkey = lock('config', LOCK_EX);
+
+ /* generate configuration XML */
+ $xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
+
+ /* write new configuration */
+ if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
+ log_error(gettext("WARNING: Config contents could not be saved. Could not open file!"));
+ unlock($lockkey);
+ file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
+ return -1;
+ }
+
+ cleanup_backupcache(true);
+
+ /* re-read configuration */
+ /* NOTE: We assume that the file can be parsed since we wrote it. */
+ $config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
+ if ($config == -1) {
+ copy("{$g['conf_path']}/config.xml", "{$g['conf_path']}/config.xml.bad");
+ $last_backup = discover_last_backup();
+ if ($last_backup) {
+ restore_backup("/cf/conf/backup/{$last_backup}");
+ $config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
+ if (platform_booting()) {
+ echo "\n\n ************** WARNING **************";
+ echo "\n\n Configuration could not be validated. A previous configuration was restored. \n";
+ echo "\n The failed configuration file has been saved as {$g['conf_path']}/config.xml.bad \n\n";
+ }
+ } else {
+ log_error(gettext("Could not restore config.xml."));
+ }
+ } else {
+ generate_config_cache($config);
+ }
+
+ unlock($lockkey);
+
+ unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
+
+ /* tell kernel to sync fs data */
+ conf_mount_ro();
+
+ /* sync carp entries to other firewalls */
+ carp_sync_client();
+
+ if (is_dir("/usr/local/pkg/write_config")) {
+ /* process packager manager custom rules */
+ run_plugins("/usr/local/pkg/write_config/");
+ }
+
+ return $config;
+}
+
+/****f* config/reset_factory_defaults
+ * NAME
+ * reset_factory_defaults - Reset the system to its default configuration.
+ * RESULT
+ * integer - indicates completion
+ ******/
+function reset_factory_defaults($lock = false) {
+ global $g;
+
+ conf_mount_rw();
+ if (!$lock) {
+ $lockkey = lock('config', LOCK_EX);
+ }
+
+ /* create conf directory, if necessary */
+ safe_mkdir("{$g['cf_conf_path']}");
+
+ /* clear out /conf */
+ $dh = opendir($g['conf_path']);
+ while ($filename = readdir($dh)) {
+ if (($filename != ".") && ($filename != "..")) {
+ unlink_if_exists($g['conf_path'] . "/" . $filename);
+ }
+ }
+ closedir($dh);
+ unlink_if_exists($g['tmp_path'] . "/config.cache");
+
+ /* copy default configuration */
+ copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
+
+ disable_security_checks();
+
+ /* call the wizard */
+ touch("/conf/trigger_initial_wizard");
+ if (!$lock) {
+ unlock($lockkey);
+ }
+ conf_mount_ro();
+ setup_serial_port();
+ return 0;
+}
+
+function config_restore($conffile) {
+ global $config, $g;
+
+ if (!file_exists($conffile)) {
+ return 1;
+ }
+
+ backup_config();
+
+ conf_mount_rw();
+
+ $lockkey = lock('config', LOCK_EX);
+
+ unlink_if_exists("{$g['tmp_path']}/config.cache");
+ copy($conffile, "{$g['cf_conf_path']}/config.xml");
+
+ disable_security_checks();
+
+ unlock($lockkey);
+
+ $config = parse_config(true);
+
+ conf_mount_ro();
+
+ write_config(gettext("Reverted to") . " " . array_pop(explode("/", $conffile)) . ".", false);
+
+ return 0;
+}
+
+function config_install($conffile) {
+ global $config, $g;
+
+ if (!file_exists($conffile)) {
+ return 1;
+ }
+
+ if (!config_validate("{$conffile}")) {
+ return 1;
+ }
+
+ if (platform_booting()) {
+ echo gettext("Installing configuration...") . "\n";
+ } else {
+ log_error(gettext("Installing configuration ...."));
+ }
+
+ conf_mount_rw();
+ $lockkey = lock('config', LOCK_EX);
+
+ copy($conffile, "{$g['conf_path']}/config.xml");
+
+ disable_security_checks();
+
+ /* unlink cache file if it exists */
+ if (file_exists("{$g['tmp_path']}/config.cache")) {
+ unlink("{$g['tmp_path']}/config.cache");
+ }
+
+ unlock($lockkey);
+ conf_mount_ro();
+
+ return 0;
+}
+
+/*
+ * Disable security checks for DNS rebind and HTTP referrer until next time
+ * they pass (or reboot), to aid in preventing accidental lockout when
+ * restoring settings like hostname, domain, IP addresses, and settings
+ * related to the DNS rebind and HTTP referrer checks.
+ * Intended for use when restoring a configuration or directly
+ * modifying config.xml without an unconditional reboot.
+ */
+function disable_security_checks() {
+ global $g;
+ touch("{$g['tmp_path']}/disable_security_checks");
+}
+
+/* Restores security checks. Should be called after all succeed. */
+function restore_security_checks() {
+ global $g;
+ unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
+}
+
+/* Returns status of security check temporary disable. */
+function security_checks_disabled() {
+ global $g;
+ return file_exists("{$g['tmp_path']}/disable_security_checks");
+}
+
+function config_validate($conffile) {
+
+ global $g, $xmlerr;
+
+ $xml_parser = xml_parser_create();
+
+ if (!($fp = fopen($conffile, "r"))) {
+ $xmlerr = gettext("XML error: unable to open file");
+ return false;
+ }
+
+ while ($data = fread($fp, 4096)) {
+ if (!xml_parse($xml_parser, $data, feof($fp))) {
+ $xmlerr = sprintf(gettext('%1$s at line %2$d'),
+ xml_error_string(xml_get_error_code($xml_parser)),
+ xml_get_current_line_number($xml_parser));
+ return false;
+ }
+ }
+ xml_parser_free($xml_parser);
+
+ fclose($fp);
+
+ return true;
+}
+
+function cleanup_backupcache($lock = false) {
+ global $g;
+ $i = false;
+
+ $revisions = get_config_backup_count();
+
+ if (!$lock) {
+ $lockkey = lock('config');
+ }
+
+ conf_mount_rw();
+
+ $backups = get_backups();
+ if ($backups) {
+ $baktimes = $backups['versions'];
+ unset($backups['versions']);
+ } else {
+ $backups = array();
+ $baktimes = array();
+ }
+ $newbaks = array();
+ $bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
+ $tocache = array();
+
+ foreach ($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
+ $backupsize = filesize($backup);
+ if ($backupsize == 0) {
+ unlink($backup);
+ continue;
+ }
+ $backupexp = explode('-', $backup);
+ $backupexp = explode('.', array_pop($backupexp));
+ $tocheck = array_shift($backupexp);
+ unset($backupexp);
+ if (!in_array($tocheck, $baktimes)) {
+ $i = true;
+ if (platform_booting()) {
+ echo ".";
+ }
+ $newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
+ if ($newxml == "-1") {
+ log_error(sprintf(gettext("The backup cache file %s is corrupted. Unlinking."), $backup));
+ unlink($backup);
+ log_error(sprintf(gettext("The backup cache file %s is corrupted. Unlinking."), $backup));
+ continue;
+ }
+ if ($newxml['revision']['description'] == "") {
+ $newxml['revision']['description'] = "Unknown";
+ }
+ if ($newxml['version'] == "") {
+ $newxml['version'] = "?";
+ }
+ $tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version'], 'filesize' => $backupsize);
+ }
+ }
+ foreach ($backups as $checkbak) {
+ if (count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
+ $newbaks[] = $checkbak;
+ } else {
+ $i = true;
+ if (platform_booting()) print " " . $tocheck . "r";
+ }
+ }
+ foreach ($newbaks as $todo) {
+ $tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version'], 'filesize' => $todo['filesize']);
+ }
+ if (is_int($revisions) and (count($tocache) > $revisions)) {
+ $toslice = array_slice(array_keys($tocache), 0, $revisions);
+ foreach ($toslice as $sliced) {
+ $newcache[$sliced] = $tocache[$sliced];
+ }
+ foreach ($tocache as $version => $versioninfo) {
+ if (!in_array($version, array_keys($newcache))) {
+ unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
+ }
+ }
+ $tocache = $newcache;
+ }
+ $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
+ fwrite($bakout, serialize($tocache));
+ fclose($bakout);
+ pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
+ conf_mount_ro();
+
+ if (!$lock) {
+ unlock($lockkey);
+ }
+}
+
+function get_backups() {
+ global $g;
+ if (file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
+ $confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
+ $bakvers = array_keys($confvers);
+ $toreturn = array();
+ sort($bakvers);
+ // $bakvers = array_reverse($bakvers);
+ foreach (array_reverse($bakvers) as $bakver) {
+ $toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
+ }
+ } else {
+ return false;
+ }
+ $toreturn['versions'] = $bakvers;
+ return $toreturn;
+}
+
+function backup_config() {
+ global $config, $g;
+
+ if ($g['platform'] == "cdrom") {
+ return;
+ }
+
+ conf_mount_rw();
+
+ /* Create backup directory if needed */
+ safe_mkdir("{$g['cf_conf_path']}/backup");
+ if ($config['revision']['time'] == "") {
+ $baktime = 0;
+ } else {
+ $baktime = $config['revision']['time'];
+ }
+
+ if ($config['revision']['description'] == "") {
+ $bakdesc = "Unknown";
+ } else {
+ $bakdesc = $config['revision']['description'];
+ }
+
+ $bakver = ($config['version'] == "") ? "?" : $config['version'];
+ $bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
+ copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
+
+ if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
+ $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
+ } else {
+ $backupcache = array();
+ }
+ $backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
+ $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
+ fwrite($bakout, serialize($backupcache));
+ fclose($bakout);
+ pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
+
+ conf_mount_ro();
+
+ return true;
+}
+
+function set_device_perms() {
+ $devices = array(
+ 'pf' => array(
+ 'user' => 'root',
+ 'group' => 'proxy',
+ 'mode' => 0660),
+ );
+
+ foreach ($devices as $name => $attr) {
+ $path = "/dev/$name";
+ if (file_exists($path)) {
+ chown($path, $attr['user']);
+ chgrp($path, $attr['group']);
+ chmod($path, $attr['mode']);
+ }
+ }
+}
+
+function get_config_user() {
+ if (empty($_SESSION["Username"])) {
+ $username = getenv("USER");
+ if (empty($conuser) || $conuser == "root") {
+ $username = "(system)";
+ }
+ } else {
+ $username = $_SESSION["Username"];
+ }
+
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
+ $username .= '@' . $_SERVER['REMOTE_ADDR'];
+ }
+
+ return $username;
+}
+
+function make_config_revision_entry($desc = null, $override_user = null) {
+ if (empty($override_user)) {
+ $username = get_config_user();
+ } else {
+ $username = $override_user;
+ }
+
+ $revision = array();
+
+ if (time() > mktime(0, 0, 0, 9, 1, 2004)) { /* make sure the clock settings are plausible */
+ $revision['time'] = time();
+ }
+
+ /* Log the running script so it's not entirely unlogged what changed */
+ if ($desc == "Unknown") {
+ $desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
+ }
+ if (!empty($desc)) {
+ $revision['description'] = "{$username}: " . $desc;
+ }
+ $revision['username'] = $username;
+ return $revision;
+}
+
+function get_config_backup_count() {
+ global $config, $g;
+ if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
+ return intval($config['system']['backupcount']);
+ } elseif ($g['platform'] == "nanobsd") {
+ return 5;
+ } else {
+ return 30;
+ }
+}
+
+function pfSense_clear_globals() {
+ global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
+
+ $error = error_get_last();
+
+ if ($error !== NULL) {
+ if ($error['type'] == E_ERROR) {
+ $errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
+ print($errorstr);
+ log_error($errorstr);
+ } else if ($error['type'] != E_NOTICE) {
+ $errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
+ // XXX: comment out for now, should re-enable post-2.2
+ //print($errorstr);
+ //log_error($errorstr);
+ }
+ }
+
+ if (isset($FilterIfList)) {
+ unset($FilterIfList);
+ }
+
+ if (isset($GatewaysList)) {
+ unset($GatewaysList);
+ }
+
+ /* Used for the hostname dns resolver */
+ if (isset($filterdns)) {
+ unset($filterdns);
+ }
+
+ /* Used for aliases and interface macros */
+ if (isset($aliases)) {
+ unset($aliases);
+ }
+ if (isset($aliastable)) {
+ unset($aliastable);
+ }
+
+ unset($config);
+}
+
+register_shutdown_function('pfSense_clear_globals');
+
+?>
diff --git a/src/etc/inc/cram_md5_sasl_client.inc b/src/etc/inc/cram_md5_sasl_client.inc
new file mode 100644
index 0000000..69bd625
--- /dev/null
+++ b/src/etc/inc/cram_md5_sasl_client.inc
@@ -0,0 +1,67 @@
+<?php
+/*
+ * cram_md5_sasl_client.php
+ *
+ * @(#) $Id: cram_md5_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
+ *
+ */
+
+define("SASL_CRAM_MD5_STATE_START", 0);
+define("SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE", 1);
+define("SASL_CRAM_MD5_STATE_DONE", 2);
+
+class cram_md5_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_CRAM_MD5_STATE_START;
+
+ Function Initialize(&$client)
+ {
+ return(1);
+ }
+
+ Function HMACMD5($key,$text)
+ {
+ $key=(strlen($key)<64 ? str_pad($key,64,"\0") : substr($key,0,64));
+ return(md5((str_repeat("\x5c", 64)^$key).pack("H32", md5((str_repeat("\x36", 64)^$key).$text))));
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if($this->state!=SASL_CRAM_MD5_STATE_START)
+ {
+ $client->error="CRAM-MD5 authentication state is not at the start";
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ "user"=>"",
+ "password"=>""
+ );
+ $defaults=array();
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if($status==SASL_CONTINUE)
+ $this->state=SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE;
+ Unset($message);
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch($this->state)
+ {
+ case SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE:
+ $message=$this->credentials["user"]." ".$this->HMACMD5($this->credentials["password"], $response);
+ $this->state=SASL_CRAM_MD5_STATE_DONE;
+ break;
+ case SASL_CRAM_MD5_STATE_DONE:
+ $client->error="CRAM-MD5 authentication was finished without success";
+ return(SASL_FAIL);
+ default:
+ $client->error="invalid CRAM-MD5 authentication step state";
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/crypt.inc b/src/etc/inc/crypt.inc
new file mode 100644
index 0000000..8d96b26
--- /dev/null
+++ b/src/etc/inc/crypt.inc
@@ -0,0 +1,101 @@
+<?php
+
+/* $Id$ */
+/*
+ Copyright (C) 2008 Shrew Soft Inc
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /usr/bin/openssl
+ pfSense_MODULE: crypto
+
+*/
+
+ function crypt_data($val, $pass, $opt) {
+ $file = tempnam("/tmp", "php-encrypt");
+ file_put_contents("{$file}.dec", $val);
+ exec("/usr/bin/openssl enc {$opt} -aes-256-cbc -in {$file}.dec -out {$file}.enc -k " . escapeshellarg($pass));
+ if (file_exists("{$file}.enc")) {
+ $result = file_get_contents("{$file}.enc");
+ } else {
+ $result = "";
+ log_error("Failed to encrypt/decrypt data!");
+ }
+ @unlink($file);
+ @unlink("{$file}.dec");
+ @unlink("{$file}.enc");
+ return $result;
+ }
+
+ function encrypt_data(& $data, $pass) {
+ return base64_encode(crypt_data($data, $pass, "-e"));
+ }
+
+ function decrypt_data(& $data, $pass) {
+ return crypt_data(base64_decode($data), $pass, "-d");
+ }
+
+ function tagfile_reformat($in, & $out, $tag) {
+
+ $out = "---- BEGIN {$tag} ----\n";
+
+ $size = 80;
+ $oset = 0;
+ while ($size >= 64) {
+ $line = substr($in, $oset, 64);
+ $out .= $line."\n";
+ $size = strlen($line);
+ $oset += $size;
+ }
+
+ $out .= "---- END {$tag} ----\n";
+
+ return true;
+ }
+
+ function tagfile_deformat($in, & $out, $tag) {
+
+ $btag_val = "---- BEGIN {$tag} ----";
+ $etag_val = "---- END {$tag} ----";
+
+ $btag_len = strlen($btag_val);
+ $etag_len = strlen($etag_val);
+
+ $btag_pos = stripos($in, $btag_val);
+ $etag_pos = stripos($in, $etag_val);
+
+ if (($btag_pos === false) || ($etag_pos === false)) {
+ return false;
+ }
+
+ $body_pos = $btag_pos + $btag_len;
+ $body_len = strlen($in);
+ $body_len -= $btag_len;
+ $body_len -= $etag_len + 1;
+
+ $out = substr($in, $body_pos, $body_len);
+
+ return true;
+ }
+
+?>
diff --git a/src/etc/inc/digest_sasl_client.inc b/src/etc/inc/digest_sasl_client.inc
new file mode 100644
index 0000000..924887d
--- /dev/null
+++ b/src/etc/inc/digest_sasl_client.inc
@@ -0,0 +1,135 @@
+<?php
+/*
+ * digest_sasl_client.php
+ *
+ * @(#) $Id: digest_sasl_client.php,v 1.1 2005/10/27 05:24:15 mlemos Exp $
+ *
+ */
+
+define('SASL_DIGEST_STATE_START', 0);
+define('SASL_DIGEST_STATE_RESPOND_CHALLENGE', 1);
+define('SASL_DIGEST_STATE_DONE', 2);
+
+class digest_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_DIGEST_STATE_START;
+
+ Function unq($string)
+ {
+ return(($string[0]=='"' && $string[strlen($string)-1]=='"') ? substr($string, 1, strlen($string)-2) : $string);
+ }
+
+ Function H($data)
+ {
+ return md5($data);
+ }
+
+ Function KD($secret, $data)
+ {
+ return $this->H($secret.':'.$data);
+ }
+
+ Function Initialize(&$client)
+ {
+ return(1);
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if($this->state!=SASL_DIGEST_STATE_START)
+ {
+ $client->error='Digest authentication state is not at the start';
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ 'user'=>'',
+ 'password'=>'',
+ 'uri'=>'',
+ 'method'=>'',
+ 'session'=>''
+ );
+ $defaults=array();
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if($status==SASL_CONTINUE)
+ $this->state=SASL_DIGEST_STATE_RESPOND_CHALLENGE;
+ Unset($message);
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch($this->state)
+ {
+ case SASL_DIGEST_STATE_RESPOND_CHALLENGE:
+ $values=explode(',',$response);
+ $parameters=array();
+ for($v=0; $v<count($values); $v++)
+ $parameters[strtok(trim($values[$v]), '=')]=strtok('');
+
+ $message='username="'.$this->credentials['user'].'"';
+ if(!IsSet($parameters[$p='realm'])
+ && !IsSet($parameters[$p='nonce']))
+ {
+ $client->error='Digest authentication parameter '.$p.' is missing from the server response';
+ return(SASL_FAIL);
+ }
+ $message.=', realm='.$parameters['realm'];
+ $message.=', nonce='.$parameters['nonce'];
+ $message.=', uri="'.$this->credentials['uri'].'"';
+ if(IsSet($parameters['algorithm']))
+ {
+ $algorithm=$this->unq($parameters['algorithm']);
+ $message.=', algorithm='.$parameters['algorithm'];
+ }
+ else
+ $algorithm='';
+
+ $realm=$this->unq($parameters['realm']);
+ $nonce=$this->unq($parameters['nonce']);
+ if(IsSet($parameters['qop']))
+ {
+ switch($qop=$this->unq($parameters['qop']))
+ {
+ case "auth":
+ $cnonce=$this->credentials['session'];
+ break;
+ default:
+ $client->error='Digest authentication quality of protection '.$qop.' is not yet supported';
+ return(SASL_FAIL);
+ }
+ }
+ $nc_value='00000001';
+ if(IsSet($parameters['qop'])
+ && !strcmp($algorithm, 'MD5-sess'))
+ $A1=$this->H($this->credentials['user'].':'. $realm.':'. $this->credentials['password']).':'.$nonce.':'.$cnonce;
+ else
+ $A1=$this->credentials['user'].':'. $realm.':'. $this->credentials['password'];
+ $A2=$this->credentials['method'].':'.$this->credentials['uri'];
+ if(IsSet($parameters['qop']))
+ $response=$this->KD($this->H($A1), $nonce.':'. $nc_value.':'. $cnonce.':'. $qop.':'. $this->H($A2));
+ else
+ $response=$this->KD($this->H($A1), $nonce.':'. $this->H($A2));
+ $message.=', response="'.$response.'"';
+ if(IsSet($parameters['opaque']))
+ $message.=', opaque='.$parameters['opaque'];
+ if(IsSet($parameters['qop']))
+ $message.=', qop="'.$qop.'"';
+ $message.=', nc='.$nc_value;
+ if(IsSet($parameters['qop']))
+ $message.=', cnonce="'.$cnonce.'"';
+ $client->encode_response=0;
+ $this->state=SASL_DIGEST_STATE_DONE;
+ break;
+ case SASL_DIGEST_STATE_DONE:
+ $client->error='Digest authentication was finished without success';
+ return(SASL_FAIL);
+ default:
+ $client->error='invalid Digest authentication step state';
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/dot.hushlogin b/src/etc/inc/dot.hushlogin
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/etc/inc/dot.hushlogin
diff --git a/src/etc/inc/dyndns.class b/src/etc/inc/dyndns.class
new file mode 100644
index 0000000..cb21fb5
--- /dev/null
+++ b/src/etc/inc/dyndns.class
@@ -0,0 +1,1634 @@
+<?php
+ /*
+ * PHP.updateDNS (pfSense version)
+ *
+ * +====================================================+
+ * Services Supported:
+ * - DynDns (dyndns.org) [dynamic, static, custom]
+ * - DHSDns (dhs.org)
+ * - No-IP (no-ip.com)
+ * - EasyDNS (easydns.com)
+ * - DHS (www.dhs.org)
+ * - HN (hn.org) -- incomplete checking!
+ * - DynS (dyns.org)
+ * - ZoneEdit (zoneedit.com)
+ * - FreeDNS (freedns.afraid.org)
+ * - Loopia (loopia.se)
+ * - StaticCling (staticcling.org)
+ * - DNSexit (dnsexit.com)
+ * - OpenDNS (opendns.com)
+ * - Namecheap (namecheap.com)
+ * - HE.net (dns.he.net)
+ * - HE.net IPv6 (dns.he.net)
+ * - HE.net Tunnelbroker IP update (ipv4.tunnelbroker.net)
+ * - SelfHost (selfhost.de)
+ * - Amazon Route 53 (aws.amazon.com)
+ * - DNS-O-Matic (dnsomatic.com)
+ * - Custom DDNS (any URL)
+ * - Custom DDNS IPv6 (any URL)
+ * - CloudFlare (www.cloudflare.com)
+ * - Eurodns (eurodns.com)
+ * - GratisDNS (gratisdns.dk)
+ * - City Network (citynetwork.se)
+ * - GleSYS (glesys.com)
+ * - DNSimple (dnsimple.com)
+ * - Google Domains (domains.google.com)
+ * - DNS Made Easy (www.dnsmadeeasy.com)
+ * +----------------------------------------------------+
+ * Requirements:
+ * - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library
+ * +----------------------------------------------------+
+ * Public Functions
+ * - updatedns()
+ *
+ * Private Functions
+ * - _update()
+ * - _checkStatus()
+ * - _error()
+ * - _detectChange()
+ * - _debug()
+ * - _checkIP()
+ * +----------------------------------------------------+
+ * DynDNS Dynamic - Last Tested: 12 July 2005
+ * DynDNS Static - Last Tested: NEVER
+ * DynDNS Custom - Last Tested: NEVER
+ * No-IP - Last Tested: 20 July 2008
+ * HN.org - Last Tested: 12 July 2005
+ * EasyDNS - Last Tested: 20 July 2008
+ * DHS - Last Tested: 12 July 2005
+ * ZoneEdit - Last Tested: NEVER
+ * Dyns - Last Tested: NEVER
+ * ODS - Last Tested: 02 August 2005
+ * FreeDNS - Last Tested: 23 Feb 2011
+ * Loopia - Last Tested: NEVER
+ * StaticCling - Last Tested: 27 April 2006
+ * DNSexit - Last Tested: 20 July 2008
+ * OpenDNS - Last Tested: 4 August 2008
+ * Namecheap - Last Tested: 31 August 2010
+ * HE.net - Last Tested: 7 July 2013
+ * HE.net IPv6 - Last Tested: 7 July 2013
+ * HE.net Tunnel - Last Tested: 28 June 2011
+ * SelfHost - Last Tested: 26 December 2011
+ * Amazon Route 53 - Last tested: 01 April 2012
+ * DNS-O-Matic - Last Tested: 9 September 2010
+ * CloudFlare - Last Tested: 30 May 2013
+ * Eurodns - Last Tested: 27 June 2013
+ * GratisDNS - Last Tested: 15 August 2012
+ * OVH DynHOST - Last Tested: NEVER
+ * City Network - Last Tested: 13 November 2013
+ * GleSYS - Last Tested: 3 February 2015
+ * DNSimple - Last Tested: 09 February 2015
+ * Google Domains - Last Tested: 27 April 2015
+ * DNS Made Easy - Last Tested: 27 April 2015
+ * +====================================================+
+ *
+ * @author E.Kristensen
+ * @link http://www.idylldesigns.com/projects/phpdns/
+ * @version 0.8
+ * @updated 13 October 05 at 21:02:42 GMT
+ *
+ * DNSexit/OpenDNS support and multiwan extension for pfSense by Ermal Luçi
+ * Custom DNS support by Matt Corallo
+ *
+ */
+
+ class updatedns {
+ var $_cacheFile;
+ var $_cacheFile_v6;
+ var $_debugFile;
+ var $_UserAgent = 'User-Agent: phpDynDNS/0.7';
+ var $_errorVerbosity = 0;
+ var $_dnsService;
+ var $_dnsUser;
+ var $_dnsPass;
+ var $_dnsHost;
+ var $_dnsIP;
+ var $_dnsWildcard;
+ var $_dnsMX;
+ var $_dnsBackMX;
+ var $_dnsServer;
+ var $_dnsPort;
+ var $_dnsUpdateURL;
+ var $_dnsZoneID;
+ var $_dnsTTL;
+ var $status;
+ var $_debugID;
+ var $_if;
+ var $_dnsResultMatch;
+ var $_dnsRequestIf;
+ var $_dnsRequestIfIP;
+ var $_dnsVerboseLog;
+ var $_curlIpresolveV4;
+ var $_curlSslVerifypeer;
+ var $_dnsMaxCacheAgeDays;
+ var $_dnsDummyUpdateDone;
+ var $_forceUpdateNeeded;
+ var $_useIPv6;
+
+ /*
+ * Public Constructor Function (added 12 July 05) [beta]
+ * - Gets the dice rolling for the update.
+ * - $dnsResultMatch should only be used with $dnsService = 'custom'
+ * - $dnsResultMatch is parsed for '%IP%', which is the IP the provider was updated to,
+ * - it is otherwise expected to be exactly identical to what is returned by the Provider.
+ * - $dnsUser, and $dnsPass indicate HTTP Auth for custom DNS, if they are needed in the URL (GET Variables), include them in $dnsUpdateURL.
+ * - $For custom requests, $dnsUpdateURL is parsed for '%IP%', which is replaced with the new IP.
+ */
+ function updatedns ($dnsService = '', $dnsHost = '', $dnsUser = '', $dnsPass = '',
+ $dnsWildcard = 'OFF', $dnsMX = '', $dnsIf = '', $dnsBackMX = '',
+ $dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false,
+ $dnsZoneID ='', $dnsTTL='', $dnsResultMatch = '', $dnsRequestIf = '',
+ $dnsID = '', $dnsVerboseLog = false, $curlIpresolveV4 = false, $curlSslVerifypeer = true) {
+
+ global $config, $g;
+
+ $this->_cacheFile = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($dnsHost) . "{$dnsID}.cache";
+ $this->_cacheFile_v6 = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($dnsHost) . "{$dnsID}_v6.cache";
+ $this->_debugFile = "{$g['varetc_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($dnsHost) . "{$dnsID}.debug";
+
+ $this->_curlIpresolveV4 = $curlIpresolveV4;
+ $this->_curlSslVerifypeer = $curlSslVerifypeer;
+ $this->_dnsVerboseLog = $dnsVerboseLog;
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDns: updatedns() starting");
+ }
+
+ $dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
+
+ if (!$dnsService) $this->_error(2);
+ switch ($dnsService) {
+ case 'freedns':
+ if (!$dnsHost) $this->_error(5);
+ break;
+ case 'namecheap':
+ if (!$dnsPass) $this->_error(4);
+ if (!$dnsHost) $this->_error(5);
+ break;
+ case 'route53':
+ if (!$dnsZoneID) $this->_error(8);
+ if (!$dnsTTL) $this->_error(9);
+ break;
+ case 'custom':
+ if (!$dnsUpdateURL) $this->_error(7);
+ break;
+ default:
+ if (!$dnsUser) $this->_error(3);
+ if (!$dnsPass) $this->_error(4);
+ if (!$dnsHost) $this->_error(5);
+ }
+
+ switch ($dnsService) {
+ case 'he-net-v6':
+ case 'custom-v6':
+ $this->_useIPv6 = true;
+ break;
+ default:
+ $this->_useIPv6 = false;
+ }
+ $this->_dnsService = strtolower($dnsService);
+ $this->_dnsUser = $dnsUser;
+ $this->_dnsPass = $dnsPass;
+ $this->_dnsHost = $dnsHost;
+ $this->_dnsServer = $dnsServer;
+ $this->_dnsPort = $dnsPort;
+ $this->_dnsWildcard = $dnsWildcard;
+ $this->_dnsMX = $dnsMX;
+ $this->_dnsZoneID = $dnsZoneID;
+ $this->_dnsTTL = $dnsTTL;
+ $this->_if = get_failover_interface($dnsIf);
+ $this->_checkIP();
+ $this->_dnsUpdateURL = $dnsUpdateURL;
+ $this->_dnsResultMatch = $dnsResultMatch;
+ $this->_dnsRequestIf = get_failover_interface($dnsRequestIf);
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDNS ({$this->_dnsHost}): running get_failover_interface for {$dnsRequestIf}. found {$this->_dnsRequestIf}");
+ }
+ $this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);
+ $this->_dnsMaxCacheAgeDays = 25;
+ $this->_dnsDummyUpdateDone = false;
+ $this->_forceUpdateNeeded = $forceUpdate;
+
+ // Ensure that we were able to lookup the IP
+ if (!is_ipaddr($this->_dnsIP)) {
+ log_error("DynDNS ({$this->_dnsHost}) There was an error trying to determine the public IP for interface - {$dnsIf}({$this->_if}). Probably interface is not a WAN interface.");
+ unlock($dyndnslck);
+ return;
+ }
+
+ $this->_debugID = rand(1000000, 9999999);
+
+ if ($forceUpdate == false && $this->_detectChange() == false) {
+ $this->_error(10);
+ } else {
+ switch ($this->_dnsService) {
+ case 'glesys':
+ case 'dnsomatic':
+ case 'dyndns':
+ case 'dyndns-static':
+ case 'dyndns-custom':
+ case 'dhs':
+ case 'noip':
+ case 'noip-free':
+ case 'easydns':
+ case 'hn':
+ case 'zoneedit':
+ case 'dyns':
+ case 'ods':
+ case 'freedns':
+ case 'loopia':
+ case 'staticcling':
+ case 'dnsexit':
+ case 'custom':
+ case 'custom-v6':
+ case 'opendns':
+ case 'namecheap':
+ case 'he-net':
+ case 'he-net-v6':
+ case 'selfhost':
+ case 'he-net-tunnelbroker':
+ case 'route53':
+ case 'cloudflare':
+ case 'eurodns':
+ case 'gratisdns':
+ case 'ovh-dynhost':
+ case 'citynetwork':
+ case 'dnsimple':
+ case 'googledomains':
+ case 'dnsmadeeasy':
+ $this->_update();
+ if ($this->_dnsDummyUpdateDone == true) {
+ // If a dummy update was needed, then sleep a while and do the update again to put the proper address back.
+ // Some providers (e.g. No-IP free accounts) need to have at least 1 address change every month.
+ // If the address has not changed recently, or the user did "Force Update", then the code does
+ // a dummy address change for providers like this.
+ sleep(10);
+ $this->_update();
+ }
+ break;
+ default:
+ $this->_error(6);
+ break;
+ }
+ }
+
+ unlock($dyndnslck);
+ }
+
+ /*
+ * Private Function (added 12 July 05) [beta]
+ * Send Update To Selected Service.
+ */
+ function _update() {
+
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDNS ({$this->_dnsHost}): DynDns _update() starting.");
+ }
+
+ if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53 ') {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+ curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $this->_dnsRequestIf);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
+ }
+
+ switch ($this->_dnsService) {
+ case 'glesys':
+ $needsIP = TRUE;
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDNS: ({$this->_dnsHost}) DNS update() starting.");
+ }
+ $server = 'https://api.glesys.com/domain/updaterecord/format/json';
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $post_data['recordid'] = $this->_dnsHost;
+ $post_data['data'] = $this->_dnsIP;
+ curl_setopt($ch, CURLOPT_URL, $server);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
+ break;
+ case 'dyndns':
+ case 'dyndns-static':
+ case 'dyndns-custom':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDNS: ({$this->_dnsHost}) DNS update() starting.");
+ }
+ if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
+ $this->_dnsWildcard = "ON";
+ }
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://members.dyndns.org/nic/update";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
+ break;
+ case 'dhs':
+ $needsIP = TRUE;
+ $post_data['hostscmd'] = 'edit';
+ $post_data['hostscmdstage'] = '2';
+ $post_data['type'] = '4';
+ $post_data['updatetype'] = 'Online';
+ $post_data['mx'] = $this->_dnsMX;
+ $post_data['mx2'] = '';
+ $post_data['txt'] = '';
+ $post_data['offline_url'] = '';
+ $post_data['cloak'] = 'Y';
+ $post_data['cloak_title'] = '';
+ $post_data['ip'] = $this->_dnsIP;
+ $post_data['domain'] = 'dyn.dhs.org';
+ $post_data['hostname'] = $this->_dnsHost;
+ $post_data['submit'] = 'Update';
+ $server = "https://members.dhs.org/nic/hosts";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, '{$server}{$port}');
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
+ break;
+ case 'noip':
+ case 'noip-free':
+ $needsIP = TRUE;
+ $server = "https://dynupdate.no-ip.com/ducupdate.php";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ if (($this->_dnsService == "noip-free") &&
+ ($this->_forceUpdateNeeded == true) &&
+ ($this->_dnsDummyUpdateDone == false)) {
+ // Update the IP to a dummy value to force No-IP free accounts to see a change.
+ $iptoset = "192.168.1.1";
+ $this->_dnsDummyUpdateDone = true;
+ log_error("DynDNS ({$this->_dnsHost}): Processing dummy update on No-IP free account. IP temporarily set to " . $iptoset);
+ } else {
+ $iptoset = $this->_dnsIP;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&pass=' . urlencode($this->_dnsPass) . '&hostname=' . $this->_dnsHost.'&ip=' . $iptoset);
+ break;
+ case 'easydns':
+ $needsIP = TRUE;
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://members.easydns.com/dyn/dyndns.php";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server . $port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard=' . $this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=' . $this->_dnsBackMX);
+ break;
+ case 'hn':
+ $needsIP = TRUE;
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "http://dup.hn.org/vanity/update";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server . $port . '?ver=1&IP=' . $this->_dnsIP);
+ break;
+ case 'zoneedit':
+ $needsIP = FALSE;
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+
+ $server = "https://dynamic.zoneedit.com/auth/dynamic.html";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, "{$server}{$port}?host=" .$this->_dnsHost);
+ break;
+ case 'dyns':
+ $needsIP = FALSE;
+ $server = "https://www.dyns.cx/postscript011.php";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&password=' . $this->_dnsPass . '&host=' . $this->_dnsHost);
+ break;
+ case 'ods':
+ $needsIP = FALSE;
+ $misc_errno = 0;
+ $misc_error = "";
+ $server = "ods.org";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ $this->con['socket'] = fsockopen("{$server}{$port}", "7070", $misc_errno, $misc_error, 30);
+ /* Check that we have connected */
+ if (!$this->con['socket']) {
+ print "error! could not connect.";
+ break;
+ }
+ /* Here is the loop. Read the incoming data (from the socket connection) */
+ while (!feof($this->con['socket'])) {
+ $this->con['buffer']['all'] = trim(fgets($this->con['socket'], 4096));
+ $code = substr($this->con['buffer']['all'], 0, 3);
+ sleep(1);
+ switch ($code) {
+ case 100:
+ fputs($this->con['socket'], "LOGIN ".$this->_dnsUser." ".$this->_dnsPass."\n");
+ break;
+ case 225:
+ fputs($this->con['socket'], "DELRR ".$this->_dnsHost." A\n");
+ break;
+ case 901:
+ fputs($this->con['socket'], "ADDRR ".$this->_dnsHost." A ".$this->_dnsIP."\n");
+ break;
+ case 795:
+ fputs($this->con['socket'], "QUIT\n");
+ break;
+ }
+ }
+ $this->_checkStatus(0, $code);
+ break;
+ case 'freedns':
+ $needIP = FALSE;
+ curl_setopt($ch, CURLOPT_URL, 'https://freedns.afraid.org/dynamic/update.php?' . $this->_dnsPass);
+ break;
+ case 'dnsexit':
+ $needsIP = TRUE;
+ curl_setopt($ch, CURLOPT_URL, 'https://www.dnsexit.com/RemoteUpdate.sv?login='.$this->_dnsUser. '&password='.$this->_dnsPass.'&host='.$this->_dnsHost.'&myip='.$this->_dnsIP);
+ break;
+ case 'loopia':
+ $needsIP = TRUE;
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ curl_setopt($ch, CURLOPT_URL, 'https://dns.loopia.se/XDynDNSServer/XDynDNS.php?hostname='.$this->_dnsHost.'&myip='.$this->_dnsIP);
+ break;
+ case 'opendns':
+ $needsIP = FALSE;
+ if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://updates.opendns.com/nic/update?hostname=". $this->_dnsHost;
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port);
+ break;
+
+ case 'staticcling':
+ $needsIP = FALSE;
+ curl_setopt($ch, CURLOPT_URL, 'https://www.staticcling.org/update.html?login='.$this->_dnsUser.'&pass='.$this->_dnsPass);
+ break;
+ case 'dnsomatic':
+ /* Example syntax
+ https://username:password@updates.dnsomatic.com/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
+ */
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("DNS-O-Matic: DNS update() starting.");
+ }
+ if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
+ $this->_dnsWildcard = "ON";
+ }
+ /*
+ Reference: https://www.dnsomatic.com/wiki/api
+ DNS-O-Matic usernames are 3-25 characters.
+ DNS-O-Matic passwords are 6-20 characters.
+ All ASCII letters and numbers accepted.
+ Dots, dashes, and underscores allowed, but not at the beginning or end of the string.
+ Required: "rawurlencode" http://www.php.net/manual/en/function.rawurlencode.php
+ Encodes the given string according to RFC 3986.
+ */
+ $server = "https://" . rawurlencode($this->_dnsUser) . ":" . rawurlencode($this->_dnsPass) . "@updates.dnsomatic.com/nic/update?hostname=";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NOCHG');
+ break;
+ case 'namecheap':
+ /* Example:
+ https://dynamicdns.park-your-domain.com/update?host=[host_name]&domain=[domain.com]&password=[domain_password]&ip=[your_ip]
+ */
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("Namecheap ({$this->_dnsHost}): DNS update() starting.");
+ }
+ $dparts = explode(".", trim($this->_dnsHost));
+ $domain_part_count = ($dparts[count($dparts)-1] == "uk") ? 3 : 2;
+ $domain_offset = count($dparts) - $domain_part_count;
+ $hostname = implode(".", array_slice($dparts, 0, $domain_offset));
+ $domain = implode(".", array_slice($dparts, $domain_offset));
+ $dnspass = trim($this->_dnsPass);
+ $server = "https://dynamicdns.park-your-domain.com/update?host={$hostname}&domain={$domain}&password={$dnspass}&ip={$this->_dnsIP}";
+ curl_setopt($ch, CURLOPT_URL, $server);
+ break;
+ case 'he-net':
+ case 'he-net-v6':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("HE.net ({$this->_dnsHost}): DNS update() starting.");
+ }
+ $server = "https://dyn.dns.he.net/nic/update?";
+ curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&password=' . $this->_dnsPass . '&myip=' . $this->_dnsIP);
+ break;
+ case 'he-net-tunnelbroker':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("HE.net Tunnelbroker: DNS update() starting.");
+ }
+ $server = "https://ipv4.tunnelbroker.net/ipv4_end.php?";
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
+ curl_setopt($ch, CURLOPT_URL, $server . 'tid=' . $this->_dnsHost);
+ break;
+ case 'selfhost':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("SelfHost: DNS update() starting.");
+ }
+ if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
+ $this->_dnsWildcard = "ON";
+ }
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://carol.selfhost.de/nic/update";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
+ break;
+ case 'route53':
+ if ($this->_dnsVerboseLog) {
+ log_error("Route53 ({$this->_dnsHost}): DNS update() starting.");
+ }
+
+ /* Setting Variables */
+ $hostname = "{$this->_dnsHost}.";
+ $ZoneID = $this->_dnsZoneID;
+ $AccessKeyId = $this->_dnsUser;
+ $SecretAccessKey = $this->_dnsPass;
+ $NewIP = $this->_dnsIP;
+ $NewTTL = $this->_dnsTTL;
+
+ /* Include Route 53 Library Class */
+ require_once('/etc/inc/r53.class');
+
+ /* Set Amazon AWS Credentials for this record */
+ $r53 = new Route53($AccessKeyId, $SecretAccessKey);
+
+ /* Function to find old values of records in Route 53 */
+ if (!function_exists('Searchrecords')) {
+ function SearchRecords($records, $name) {
+ $result = array();
+ foreach ($records as $record) {
+ if (strtolower($record['Name']) == strtolower($name)) {
+ $result [] = $record;
+ }
+ }
+ return ($result) ? $result : false;
+ }
+ }
+
+ $records = $r53->listResourceRecordSets("/hostedzone/$ZoneID");
+
+ /* Get IP for your hostname in Route 53 */
+ if (false !== ($a_result = SearchRecords($records['ResourceRecordSets'], "$hostname"))) {
+ $OldTTL = $a_result[0][TTL];
+ $OldIP = $a_result[0][ResourceRecords][0];
+ } else {
+ $OldIP = "";
+ }
+
+ /* Check if we need to update DNS Record */
+ if ($OldIP !== $NewIP) {
+ if (!empty($OldIP)) {
+ /* Your Hostname already exists, deleting and creating it again */
+ $changes = array();
+ $changes[] = $r53->prepareChange(DELETE, $hostname, A, $OldTTL, $OldIP);
+ $changes[] = $r53->prepareChange(CREATE, $hostname, A, $NewTTL, $NewIP);
+ $result = $r53->changeResourceRecordSets("/hostedzone/$ZoneID", $changes);
+ } else {
+ /* Your Hostname does not exist yet, creating it */
+ $changes = $r53->prepareChange(CREATE, $hostname, A, $NewTTL, $NewIP);
+ $result = $r53->changeResourceRecordSets("/hostedzone/$ZoneID", $changes);
+ }
+ }
+ $this->_checkStatus(0, $result);
+ break;
+ case 'custom':
+ case 'custom-v6':
+ if ($this->_dnsVerboseLog) {
+ log_error("Custom DDNS ({$this->_dnsHost}): DNS update() starting.");
+ }
+ if (strstr($this->dnsUpdateURL, "%IP%")) {$needsIP = TRUE;} else {$needsIP = FALSE;}
+ if ($this->_dnsUser != '') {
+ if ($this->_curlIpresolveV4) {
+ curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ }
+ if ($this->_curlSslVerifypeer) {
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
+ } else {
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ }
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ curl_setopt($ch, CURLOPT_USERPWD, "{$this->_dnsUser}:{$this->_dnsPass}");
+ }
+ $server = str_replace("%IP%", $this->_dnsIP, $this->_dnsUpdateURL);
+ if ($this->_dnsVerboseLog) {
+ log_error("Sending request to: ".$server);
+ }
+ curl_setopt($ch, CURLOPT_URL, $server);
+ break;
+ case 'cloudflare':
+ $needsIP = TRUE;
+ $dnsServer ='www.cloudflare.com';
+ $dnsHost = str_replace(' ', '', $this->_dnsHost);
+ $URL = "https://{$dnsServer}/api.html?a=DIUP&email={$this->_dnsUser}&tkn={$this->_dnsPass}&ip={$this->_dnsIP}&hosts={$dnsHost}";
+ curl_setopt($ch, CURLOPT_URL, $URL);
+ break;
+ case 'eurodns':
+ $needsIP = TRUE;
+ if ($this->_dnsVerboseLog) {
+ log_error("EuroDynDns ({$this->_dnsHost}) DNS update() starting.");
+ }
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://update.eurodyndns.org/update/";
+ $port = "";
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
+ break;
+ case 'gratisdns':
+ $needsIP = TRUE;
+ if ($this->_dnsVerboseLog) {
+ log_error("GratisDNS.dk ({$this->_dnsHost}): DNS update() starting.");
+ }
+ $server = "https://ssl.gratisdns.dk/ddns.phtml";
+ list($hostname, $domain) = explode(".", $this->_dnsHost, 2);
+ curl_setopt($ch, CURLOPT_URL, $server . '?u=' . $this->_dnsUser . '&p=' . $this->_dnsPass . '&h=' . $this->_dnsHost . '&d=' . $domain . '&i=' . $this->_dnsIP);
+ break;
+ case 'ovh-dynhost':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("OVH DynHOST: ({$this->_dnsHost}) DNS update() starting.");
+ }
+ if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = "https://www.ovh.com/nic/update";
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
+ break;
+ case 'citynetwork':
+ $needsIP = TRUE;
+ if ($this->_dnsVerboseLog) {
+ log_error("City Network: ({$this->_dnsHost}) DNS update() starting.");
+ }
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ $server = 'https://dyndns.citynetwork.se/nic/update';
+ $port = "";
+ if ($this->_dnsServer) {
+ $server = $this->_dnsServer;
+ }
+ if ($this->_dnsPort) {
+ $port = ":" . $this->_dnsPort;
+ }
+ curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
+ break;
+ case 'dnsimple':
+ /* Uses DNSimple's REST API
+ Requires username and Account API token passed in header
+ Piggybacks on Route 53's ZoneID field for DNSimple record ID
+ Data sent as JSON */
+ $needsIP = TRUE;
+ $server = 'https://api.dnsimple.com/v1/domains/';
+ $token = $this->_dnsUser . ':' . $this->_dnsPass;
+ $jsondata = '{"record":{"content":"' . $this->_dnsIP . '","ttl":"' . $this->_dnsTTL . '"}}';
+ curl_setopt($ch, CURLOPT_HEADER, 1);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'X-DNSimple-Token: ' . $token));
+ curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '/records/' . $this->_dnsZoneID);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $jsondata);
+ break;
+ case 'googledomains':
+ $needsIP = FALSE;
+ if ($this->_dnsVerboseLog) {
+ log_error("Google Domains: ({$this->_dnsHost}) DNS update() starting.");
+ }
+ $post_data['username:password'] = $this->_dnsUser . ':' . $this->_dnsPass;
+ $post_data['hostname'] = $this->_dnsHost;
+ $post_data['myip'] = $this->_dnsIP;
+ $post_data['offline'] = 'no';
+ $server = "https://domains.google.com/nic/update";
+ $port = "";
+ curl_setopt($ch, CURLOPT_URL, 'https://domains.google.com/nic/update');
+ curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
+ break;
+ case 'dnsmadeeasy':
+ $needsIP = TRUE;
+ if ($this->_dnsVerboseLog) {
+ log_error("DNS Made Easy ({$this->_dnsHost}): DNS update() starting.");
+ }
+ $server = "https://cp.dnsmadeeasy.com/servlet/updateip";
+ curl_setopt($ch, CURLOPT_URL, $server . '?username=' . $this->_dnsUser . '&password=' . $this->_dnsPass . '&id=' . $this->_dnsHost . '&ip=' . $this->_dnsIP);
+ break;
+ default:
+ break;
+ }
+ if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53') {
+ $data = curl_exec($ch);
+ $this->_checkStatus($ch, $data);
+ @curl_close($ch);
+ }
+ }
+
+ /*
+ * Private Function (added 12 July 2005) [beta]
+ * Retrieve Update Status
+ */
+ function _checkStatus($ch, $data) {
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDNS ({$this->_dnsHost}): DynDns _checkStatus() starting.");
+ log_error("DynDNS ({$this->_dnsHost}): Current Service: {$this->_dnsService}");
+ }
+ $successful_update = false;
+ if ($this->_dnsService != 'ods' and $this->_dnsService != 'route53' && @curl_error($ch)) {
+ $status = "Curl error occurred: " . curl_error($ch);
+ log_error($status);
+ $this->status = $status;
+ return;
+ }
+ switch ($this->_dnsService) {
+ case 'glesys':
+ if (preg_match('/Record updated/i', $data)) {
+ $status = "GleSYS ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else {
+ $status = "GleSYS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("GleSYS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dnsomatic':
+ if (preg_match('/badauth/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): The DNS-O-Matic username or password specified are incorrect. No updates will be distributed to services until this is resolved.";
+ } else if (preg_match('/notfqdn /i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): The hostname specified is not a fully-qualified domain name. If no hostnames included, notfqdn will be returned once.";
+ } else if (preg_match('/nohost/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): The hostname passed could not be matched to any services configured. The service field will be blank in the return code.";
+ } else if (preg_match('/numhost/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): You may update up to 20 hosts. numhost is returned if you try to update more than 20 or update a round-robin.";
+ } else if (preg_match('/abuse/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): The hostname is blocked for update abuse.";
+ } else if (preg_match('/good/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/dnserr/i', $data)) {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): DNS error encountered. Stop updating for 30 minutes.";
+ } else {
+ $status = "DNS-O-Matic ({$this->_dnsHost}): (Unknown Response)";
+ log_error("DNS-O-Matic ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'citynetwork':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Not A FQDN!";
+ } else if (preg_match('/nohost/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) No such host";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'ovh-dynhost':
+ case 'dyndns':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Not A FQDN!";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/noauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dyndns-static':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Not A FQDN!";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/noauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dyndns-custom':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Not A FQDN!";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS: (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/noauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dhs':
+ break;
+ case 'noip':
+ case 'noip-free':
+ list($ip, $code) = explode(":", $data);
+ switch ($code) {
+ case 0:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP address is current, no update performed.";
+ $successful_update = true;
+ break;
+ case 1:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) DNS hostname update successful.";
+ $successful_update = true;
+ break;
+ case 2:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Hostname supplied does not exist.";
+ break;
+ case 3:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Invalid Username.";
+ break;
+ case 4:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Invalid Password.";
+ break;
+ case 5:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) To many updates sent.";
+ break;
+ case 6:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Account disabled due to violation of No-IP terms of service.";
+ break;
+ case 7:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Invalid IP. IP Address submitted is improperly formatted or is a private IP address or is on a blacklist.";
+ break;
+ case 8:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Disabled / Locked Hostname.";
+ break;
+ case 9:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Host updated is configured as a web redirect and no update was performed.";
+ break;
+ case 10:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Group supplied does not exist.";
+ break;
+ case 11:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) DNS group update is successful.";
+ $successful_update = true;
+ break;
+ case 12:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) DNS group is current, no update performed.";
+ $successful_update = true;
+ break;
+ case 13:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Update client support not available for supplied hostname or group.";
+ break;
+ case 14:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Hostname supplied does not have offline settings configured.";
+ break;
+ case 99:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Client disabled. Client should exit and not perform any more updates without user intervention.";
+ break;
+ case 100:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Client disabled. Client should exit and not perform any more updates without user intervention.";
+ break;
+ default:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ $this->_debug("Unknown Response: ".$data);
+ break;
+ }
+ break;
+ case 'easydns':
+ if (preg_match('/NOACCESS/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Authentication Failed: Username and/or Password was Incorrect.";
+ } else if (preg_match('/NOSERVICE/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) No Service: Dynamic DNS Service has been disabled for this domain.";
+ } else if (preg_match('/ILLEGAL INPUT/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Illegal Input: Self-Explanatory";
+ } else if (preg_match('/TOOSOON/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Too Soon: Not Enough Time Has Elapsed Since Last Update";
+ } else if (preg_match('/NOERROR/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'hn':
+ /* FIXME: add checks */
+ break;
+ case 'zoneedit':
+ if (preg_match('/799/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error 799) Update Failed!";
+ } else if (preg_match('/700/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error 700) Update Failed!";
+ } else if (preg_match('/200/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/201/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dyns':
+ if (preg_match("/400/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Bad Request - The URL was malformed. Required parameters were not provided.";
+ } else if (preg_match('/402/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Update Too Soon - You have tried updating to quickly since last change.";
+ } else if (preg_match('/403/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Database Error - There was a server-sided database error.";
+ } else if (preg_match('/405/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Hostname Error - The hostname (".$this->_dnsHost.") doesn't belong to you.";
+ } else if (preg_match('/200/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'ods':
+ if (preg_match("/299/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'freedns':
+ if (preg_match("/has not changed./i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match("/Updated/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dnsexit':
+ if (preg_match("/is the same/i", $data)) {
+ $status = "phpDynDns ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match("/Success/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'loopia':
+ if (preg_match("/nochg/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match("/good/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'opendns':
+ if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS({$this->_dnsHost}): (Error) Not a valid username or password!";
+ } else if (preg_match('/nohost/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Hostname you are trying to update does not exist.";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/yours/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) hostname specified exists, but not under the username specified.";
+ } else if (preg_match('/abuse/i', $data)) {
+ $status = "phpDynDns ({$this->_dnsHost}): (Error) Updating too frequently, considered abuse.";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'staticcling':
+ if (preg_match("/invalid ip/i", $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Bad Request - The IP provided was invalid.";
+ } else if (preg_match('/required info missing/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Bad Request - Required parameters were not provided.";
+ } else if (preg_match('/invalid characters/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Bad Request - Illegal characters in either the username or the password.";
+ } else if (preg_match('/bad password/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Invalid password.";
+ } else if (preg_match('/account locked/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) This account has been administratively locked.";
+ } else if (preg_match('/update too frequent/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Updating too frequently.";
+ } else if (preg_match('/DB error/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Server side error.";
+ } else if (preg_match('/success/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'namecheap':
+ $tmp = str_replace("^M", "", $data);
+ $ncresponse = @xml2array($tmp);
+ if (preg_match("/internal server error/i", $data)) {
+ $status = "phpDynDNS: (Error) Server side error.";
+ } else if (preg_match("/request is badly formed/i", $data)) {
+ $status = "phpDynDNS: (Error) Badly Formed Request (check your settings).";
+ } else if ($ncresponse['interface-response']['ErrCount'] === "0") {
+ $status = "phpDynDNS: (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else if (is_numeric($ncresponse['interface-response']['ErrCount']) && ($ncresponse['interface-response']['ErrCount'] > 0)) {
+ $status = "phpDynDNS: (Error) " . implode(", ", $ncresponse["interface-response"]["errors"]);
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+
+ case 'he-net':
+ case 'he-net-v6':
+ if (preg_match("/badip/i", $data)) {
+ $status = "phpDynDNS: (Error) Bad Request - The IP provided was invalid.";
+ } else if (preg_match('/nohost/i', $data)) {
+ $status = "phpDynDNS: (Error) Bad Request - A hostname was not provided.";
+ } else if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS: (Error) Invalid username or password.";
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS: (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS: (Success) No Change In IP Address.";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'he-net-tunnelbroker':
+ /*
+ -ERROR: Missing parameter(s).
+ -ERROR: Invalid API key or password
+ -ERROR: Tunnel not found
+ -ERROR: Another tunnel exists for this IP.
+ -ERROR: This tunnel is already associated with this IP address
+ +OK: Tunnel endpoint updated to: x.x.x.x
+ */
+ if (preg_match("/Missing parameter/i", $data)) {
+ $status = "phpDynDNS: (Error) Bad Request - Missing/Invalid Parameters.";
+ } else if (preg_match('/Tunnel not found/i', $data)) {
+ $status = "phpDynDNS: (Error) Bad Request - Invalid Tunnel ID.";
+ } else if (preg_match('/Invalid API key or password/i', $data)) {
+ $status = "phpDynDNS: (Error) Invalid username or password.";
+ } else if (preg_match('/OK:/i', $data)) {
+ $status = "phpDynDNS: (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else if (preg_match('/This tunnel is already associated with this IP address/i', $data)) {
+ $status = "phpDynDNS: (Success) No Change In IP Address.";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'selfhost':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS: (Error) Not A FQDN!";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS: (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS: (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/noauth/i', $data)) {
+ $status = "phpDynDNS: (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'route53':
+ $successful_update = true;
+ break;
+ case 'custom':
+ case 'custom-v6':
+ $successful_update = false;
+ if ($this->_dnsResultMatch == "") {
+ $successful_update = true;
+ } else {
+ $this->_dnsResultMatch = str_replace("%IP%", $this->_dnsIP, $this->_dnsResultMatch);
+ $matches = preg_split("/(?<!\\\\)\\|/", $this->_dnsResultMatch);
+ foreach ($matches as $match) {
+ $match= str_replace("\\|", "|", $match);
+ if (strcmp($match, trim($data, "\t\n\r")) == 0) {
+ $successful_update = true;
+ }
+ }
+ unset ($matches);
+ }
+ if ($successful_update == true) {
+ $status = "phpDynDNS: (Success) IP Address Updated Successfully!";
+ } else {
+ $status = "phpDynDNS: (Error) Result did not match.";
+ }
+ break;
+ case 'cloudflare':
+ // receive multiple results
+ $data = explode("\n", $data);
+ $lines = count($data)-1;
+
+ // loop over the lines
+ for ($pos = 0; ($successful_update || $pos == 0) && $pos < $lines; $pos++) {
+ $resp = $data[$pos];
+ if (preg_match('/UAUTH/i', $resp)) {
+ $status = "DynDNS: The username specified is not authorized to update this hostname and domain.";
+ } else if (preg_match('/NOHOST/i', $resp)) {
+ $status = "DynDNS: No valid FQDN (fully qualified domain name) was specified";
+ } else if (preg_match('/INVLDHST/i', $resp)) {
+ $status = "DynDNS: An invalid hostname was specified. This may be due to the fact the hostname has not been created in the system. Creating new host names via clients is not supported.";
+ } else if (preg_match('/INVLDIP/i', $resp)) {
+ $status = "DynDNS: The IP address given is not valid.";
+ } else if (preg_match('/DUPHST/i', $resp)) {
+ $status = "DynDNS: Duplicate values exist for a record. Only single values for records are supported currently.";
+ } else if (preg_match('/NOUPDATE/i', $resp)) {
+ $status = "DynDNS: No changes made to the hostname (" . strtok($resp, ' ') . "). Continual updates with no changes lead to blocked clients.";
+ $successful_update = true; //success if it is the same so that it saves
+ } else if (preg_match('/OK/i', $resp)) {
+ $status = "DynDNS: (Success) (" . strtok($resp, ' ') . ") IP Address for Changed Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "DynDNS: (Unknown Response)";
+ log_error("DynDNS: PAYLOAD: {$resp}");
+ $this->_debug($resp);
+ }
+ log_error($status);
+ }
+ break;
+ case 'eurodns':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS: (Error) Not A FQDN!";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS: (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS: (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS: (Error) User Authorization Failed";
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'gratisdns':
+ if (preg_match('/Forkerte værdier/i', $data)) {
+ $status = "phpDynDNS: (Error) Wrong values - Update could not be completed.";
+ } else if (preg_match('/Bruger login: Bruger eksistere ikke/i', $data)) {
+ $status = "phpDynDNS: (Error) Unknown username - User does not exist.";
+ } else if (preg_match('/Bruger login: 1Fejl i kodeord/i', $data)) {
+ $status = "phpDynDNS: (Error) Wrong password - Remember password is case sensitive.";
+ } else if (preg_match('/Domæne kan IKKE administreres af bruger/i', $data)) {
+ $status = "phpDynDNS: (Error) User unable to administer the selected domain.";
+ } else if (preg_match('/OK/i', $data)) {
+ $status = "phpDynDNS: (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else {
+ $status = "phpDynDNS: (Unknown Response)";
+ log_error("phpDynDNS: PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dnsimple':
+ /* Responds with HTTP 200 on success.
+ Responds with HTTP 4xx on error.
+ Returns JSON data as body */
+ $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $header = substr($data, 0, $header_size);
+ $body = substr($data, $header_size);
+ if (preg_match("/Status: 200\s/i", $header)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Updated Successfully!";
+ $successful_update = true;
+ } else if (preg_match("/Status: 4\d\d\s/i", $header)) {
+ $arrbody = json_decode($body, true);
+ $message = $arrbody['message'] . ".";
+ if (isset($arrbody['errors']['content'])) {
+ foreach ($arrbody['errors']['content'] as $key => $content) {
+ $message .= " " . $content . ".";
+ }
+ }
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) " . $message;
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$body}");
+ $this->_debug($body);
+ }
+ break;
+ case 'googledomains':
+ if (preg_match('/notfqdn/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Not A FQDN";
+ } else if (preg_match('/nochg/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) No Change In IP Address";
+ $successful_update = true;
+ } else if (preg_match('/good/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ } else if (preg_match('/badauth/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) User Authorization Failed";
+ } else if (preg_match('/nohost/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Hostname does not exist or DynDNS not enabled";
+ } else if (preg_match('/badagent/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Bad request";
+ } else if (preg_match('/abuse/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Dynamic DNS access has been blocked!";
+ } else if (preg_match('/911/i', $data)) {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Error on Google's end, retry in 5 minutes";
+ } else {
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ }
+ break;
+ case 'dnsmadeeasy':
+ switch ($data) {
+ case 'success':
+ $status = "phpDynDNS({$this->_dnsHost}): (Success) IP Address Changed Successfully! (" . $this->_dnsIP . ")";
+ $successful_update = true;
+ break;
+ case 'error-auth':
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Invalid username or password";
+ break;
+ case 'error-auth-suspend':
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Account suspended";
+ break;
+ case 'error-auth-voided':
+ $status = "phpDynDNS ({$this->_dnsHost}): (Error) Account revoked";
+ break;
+ case 'error-record-invalid':
+ $status = "phpDynDns ({$this->_dnsHost}): (Error) Record does not exist in the system. Unable to update record";
+ break;
+ case 'error-record-auth':
+ $status = "phpDynDns ({$this->_dnsHost}): (Error) User does not have access to this record";
+ break;
+ case 'error-record-ip-same':
+ $status = "phpDynDns ({$this->_dnsHost}): (Success) No change in IP Address";
+ $successful_update = true;
+ break;
+ case 'error-system':
+ $status = "phpDynDns ({$this->_dnsHost}): (Error) General system error recognized by the system";
+ break;
+ case 'error':
+ $status = "phpDynDns ({$this->_dnsHost}): (Error) General system error unrecognized by the system";
+ break;
+ default:
+ $status = "phpDynDNS ({$this->_dnsHost}): (Unknown Response)";
+ log_error("phpDynDNS ({$this->_dnsHost}): PAYLOAD: {$data}");
+ $this->_debug($data);
+ break;
+ }
+ break;
+ }
+
+ if ($successful_update == true) {
+ /* Write WAN IP to cache file */
+ $wan_ip = $this->_checkIP();
+ conf_mount_rw();
+ if ($this->_useIPv6 == false && $wan_ip > 0) {
+ $currentTime = time();
+ notify_all_remote(sprintf(gettext("DynDNS updated IP Address on %s (%s) to %s"), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
+ log_error("phpDynDNS: updating cache file {$this->_cacheFile}: {$wan_ip}");
+ @file_put_contents($this->_cacheFile, "{$wan_ip}:{$currentTime}");
+ } else {
+ @unlink($this->_cacheFile);
+ }
+ if ($this->_useIPv6 == true && $wan_ip > 0) {
+ $currentTime = time();
+ notify_all_remote(sprintf(gettext("DynDNS updated IPv6 Address on %s (%s) to %s"), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
+ log_error("phpDynDNS: updating cache file {$this->_cacheFile_v6}: {$wan_ip}");
+ @file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
+ } else {
+ @unlink($this->_cacheFile_v6);
+ }
+ conf_mount_ro();
+ }
+ $this->status = $status;
+ log_error($status);
+ }
+
+ /*
+ * Private Function (added 12 July 05) [beta]
+ * Return Error, Set Last Error, and Die.
+ */
+ function _error($errorNumber = '1') {
+ switch ($errorNumber) {
+ case 0:
+ break;
+ case 2:
+ $error = 'phpDynDNS: (ERROR!) No Dynamic DNS Service provider was selected.';
+ break;
+ case 3:
+ $error = 'phpDynDNS: (ERROR!) No Username Provided.';
+ break;
+ case 4:
+ $error = 'phpDynDNS: (ERROR!) No Password Provided.';
+ break;
+ case 5:
+ $error = 'phpDynDNS: (ERROR!) No Hostname Provided.';
+ break;
+ case 6:
+ $error = 'phpDynDNS: (ERROR!) The Dynamic DNS Service provided is not yet supported.';
+ break;
+ case 7:
+ $error = 'phpDynDNS: (ERROR!) No Update URL Provided.';
+ break;
+ case 8:
+ $status = "Route 53: (Error) Invalid ZoneID";
+ break;
+ case 9:
+ $status = "Route 53: (Error) Invalid TTL";
+ break;
+ case 10:
+ $error = "phpDynDNS ({$this->_dnsHost}): No change in my IP address and/or " . $this->_dnsMaxCacheAgeDays . " days has not passed. Not updating dynamic DNS entry.";
+ break;
+ default:
+ $error = "phpDynDNS: (ERROR!) Unknown Response.";
+ /* FIXME: $data isn't in scope here */
+ /* $this->_debug($data); */
+ break;
+ }
+ $this->lastError = $error;
+ log_error($error);
+ }
+
+ /*
+ * Private Function (added 12 July 05) [beta]
+ * - Detect whether or not IP needs to be updated.
+ * | Written Specifically for pfSense (https://www.pfsense.org) may
+ * | work with other systems. pfSense base is FreeBSD.
+ */
+ function _detectChange() {
+ global $debug;
+
+ if ($debug) {
+ log_error("DynDns ({$this->_dnsHost}): _detectChange() starting.");
+ }
+
+ $currentTime = time();
+
+ $wan_ip = $this->_checkIP();
+ if ($wan_ip == 0) {
+ log_error("DynDns ({$this->_dnsHost}): Current WAN IP could not be determined, skipping update process.");
+ return false;
+ }
+ $log_error = "DynDns ({$this->_dnsHost}): Current WAN IP: {$wan_ip} ";
+
+ if ($this->_useIPv6 == true) {
+ if (file_exists($this->_cacheFile_v6)) {
+ $contents = file_get_contents($this->_cacheFile_v6);
+ list($cacheIP, $cacheTime) = explode('|', $contents);
+ $this->_debug($cacheIP.'/'.$cacheTime);
+ $initial = false;
+ $log_error .= "Cached IPv6: {$cacheIP} ";
+ } else {
+ conf_mount_rw();
+ $cacheIP = '::';
+ @file_put_contents($this->_cacheFile, "::|{$currentTime}");
+ conf_mount_ro();
+ $cacheTime = $currentTime;
+ $initial = true;
+ $log_error .= "No Cached IPv6 found.";
+ }
+ } else {
+ if (file_exists($this->_cacheFile)) {
+ $contents = file_get_contents($this->_cacheFile);
+ list($cacheIP, $cacheTime) = explode(':', $contents);
+ $this->_debug($cacheIP.'/'.$cacheTime);
+ $initial = false;
+ $log_error .= "Cached IP: {$cacheIP} ";
+ } else {
+ conf_mount_rw();
+ $cacheIP = '0.0.0.0';
+ @file_put_contents($this->_cacheFile, "0.0.0.0:{$currentTime}");
+ conf_mount_ro();
+ $cacheTime = $currentTime;
+ $initial = true;
+ $log_error .= "No Cached IP found.";
+ }
+ }
+ if ($this->_dnsVerboseLog) {
+ log_error($log_error);
+ }
+
+ // Convert seconds = days * hr/day * min/hr * sec/min
+ $maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
+
+ $needs_updating = FALSE;
+ /* lets determine if the item needs updating */
+ if ($cacheIP != $wan_ip) {
+ $needs_updating = true;
+ $update_reason = "DynDns: cacheIP != wan_ip. Updating. ";
+ $update_reason .= "Cached IP: {$cacheIP} WAN IP: {$wan_ip} ";
+ }
+ if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
+ $needs_updating = true;
+ $this->_forceUpdateNeeded = true;
+ $update_reason = "DynDns: More than " . $this->_dnsMaxCacheAgeDays . " days. Updating. ";
+ $update_reason .= "{$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
+ }
+ if ($initial == true) {
+ $needs_updating = true;
+ $update_reason .= "Initial update. ";
+ }
+
+ /* finally if we need updating then store the
+ * new cache value and return true
+ */
+ if ($needs_updating == true) {
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDns ({$this->_dnsHost}): {$update_reason}");
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
+ * Private Function (added 16 July 05) [beta]
+ * - Writes debug information to a file.
+ * - This function is only called when a unknown response
+ * - status is returned from a DynDNS service provider.
+ */
+ function _debug($data) {
+ global $g;
+
+ if (!$g['debug']) {
+ return;
+ }
+ $string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
+ conf_mount_rw();
+ $file = fopen($this->_debugFile, 'a');
+ fwrite($file, $string);
+ fclose($file);
+ conf_mount_ro();
+ }
+ function _checkIP() {
+ global $debug;
+
+ if ($debug) {
+ log_error("DynDns ({$this->_dnsHost}): _checkIP() starting.");
+ }
+
+ if ($this->_useIPv6 == true) {
+ $ip_address = find_interface_ipv6($this->_if);
+ if (!is_ipaddrv6($ip_address)) {
+ return 0;
+ }
+ } else {
+ $ip_address = find_interface_ip($this->_if);
+ if (!is_ipaddr($ip_address)) {
+ return 0;
+ }
+ }
+ if ($this->_useIPv6 == false && is_private_ip($ip_address)) {
+ $hosttocheck = "checkip.dyndns.org";
+ $try = 0;
+ while ($try < 3) {
+ $checkip = gethostbyname($hosttocheck);
+ if (is_ipaddr($checkip)) {
+ break;
+ }
+ $try++;
+ }
+ if ($try >= 3) {
+ log_error("Dyndns debug information ({$this->_dnsHost}): Could not resolve {$hosttocheck} to IP using interface IP {$ip_address}.");
+ return 0;
+ }
+ $ip_ch = curl_init("http://{$checkip}");
+ curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
+ curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
+ curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
+ if ($this->_useIPv6 == false) {
+ curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ }
+ $ip_result_page = curl_exec($ip_ch);
+ curl_close($ip_ch);
+ $ip_result_decoded = urldecode($ip_result_page);
+ preg_match('/Current IP Address: (.*)<\/body>/', $ip_result_decoded, $matches);
+ $ip_address = trim($matches[1]);
+ if (is_ipaddr($ip_address)) {
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDns ({$this->_dnsHost}): {$ip_address} extracted from {$hosttocheck}");
+ }
+ } else {
+ log_error("DynDns ({$this->_dnsHost}): IP address could not be extracted from {$hosttocheck}");
+ return 0;
+ }
+ } else {
+ if ($this->_dnsVerboseLog) {
+ log_error("DynDns ({$this->_dnsHost}): {$ip_address} extracted from local system.");
+ }
+ }
+ $this->_dnsIP = $ip_address;
+
+ return $ip_address;
+ }
+
+ }
+
+?>
diff --git a/src/etc/inc/easyrule.inc b/src/etc/inc/easyrule.inc
new file mode 100644
index 0000000..c46e84d
--- /dev/null
+++ b/src/etc/inc/easyrule.inc
@@ -0,0 +1,495 @@
+<?php
+/*
+ easyrule.inc
+
+ Copyright (C) 2009-2010 Jim Pingle (jpingle@gmail.com)
+ Originally Sponsored By Anathematic @ pfSense Forums
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ pfSense_BUILDER_BINARIES:
+ pfSense_MODULE: filter
+*/
+
+$blockaliasname = 'EasyRuleBlockHosts';
+$protocols_with_ports = array('tcp', 'udp');
+require_once("functions.inc");
+require_once("util.inc");
+require_once("config.inc");
+
+function easyrule_find_rule_interface($int) {
+ global $config;
+ /* Borrowed from firewall_rules.php */
+ $iflist = get_configured_interface_with_descr(false, true);
+
+ if ($config['pptpd']['mode'] == "server") {
+ $iflist['pptp'] = "PPTP VPN";
+ }
+
+ if ($config['pppoe']['mode'] == "server") {
+ $iflist['pppoe'] = "PPPoE Server";
+ }
+
+ if ($config['l2tp']['mode'] == "server") {
+ $iflist['l2tp'] = "L2TP VPN";
+ }
+
+ /* add ipsec interfaces */
+ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
+ $iflist["enc0"] = "IPSEC";
+ }
+
+ if (isset($iflist[$int])) {
+ return $int;
+ }
+
+ foreach ($iflist as $if => $ifd) {
+ if (strtolower($int) == strtolower($ifd)) {
+ return $if;
+ }
+ }
+
+ if (substr($int, 0, 4) == "ovpn") {
+ return "openvpn";
+ }
+
+ return false;
+}
+
+function easyrule_block_rule_exists($int = 'wan', $ipproto = "inet") {
+ global $blockaliasname, $config;
+ /* No rules, we we know it doesn't exist */
+ if (!is_array($config['filter']['rule'])) {
+ return false;
+ }
+
+ /* Search through the rules for one referencing our alias */
+ foreach ($config['filter']['rule'] as $rule) {
+ if (!is_array($rule) || !is_array($rule['source'])) {
+ continue;
+ }
+ $checkproto = isset($rule['ipprotocol']) ? $rule['ipprotocol'] : "inet";
+ if ($rule['source']['address'] == $blockaliasname . strtoupper($int) && ($rule['interface'] == $int) && ($checkproto == $ipproto)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function easyrule_block_rule_create($int = 'wan', $ipproto = "inet") {
+ global $blockaliasname, $config;
+ /* If the alias doesn't exist, exit.
+ * Can't create an empty alias, and we don't know a host */
+ if (easyrule_block_alias_getid($int) === false) {
+ return false;
+ }
+
+ /* If the rule already exists, no need to do it again */
+ if (easyrule_block_rule_exists($int, $ipproto)) {
+ return true;
+ }
+
+ /* No rules, start a new array */
+ if (!is_array($config['filter']['rule'])) {
+ $config['filter']['rule'] = array();
+ }
+
+ filter_rules_sort();
+ $a_filter = &$config['filter']['rule'];
+
+ /* Make up a new rule */
+ $filterent = array();
+ $filterent['type'] = 'block';
+ $filterent['interface'] = $int;
+ $filterent['ipprotocol'] = $ipproto;
+ $filterent['source']['address'] = $blockaliasname . strtoupper($int);
+ $filterent['destination']['any'] = '';
+ $filterent['descr'] = gettext("Easy Rule: Blocked from Firewall Log View");
+ $filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
+
+ array_splice($a_filter, 0, 0, array($filterent));
+
+ return true;
+}
+
+function easyrule_block_alias_getid($int = 'wan') {
+ global $blockaliasname, $config;
+ if (!is_array($config['aliases'])) {
+ return false;
+ }
+
+ /* Hunt down an alias with the name we want, return its id */
+ foreach ($config['aliases']['alias'] as $aliasid => $alias) {
+ if ($alias['name'] == $blockaliasname . strtoupper($int)) {
+ return $aliasid;
+ }
+ }
+
+ return false;
+}
+
+function easyrule_block_alias_add($host, $int = 'wan') {
+ global $blockaliasname, $config;
+ /* If the host isn't a valid IP address, bail */
+ $host = trim($host, "[]");
+ if (!is_ipaddr($host) && !is_subnet($host)) {
+ return false;
+ }
+
+ /* If there are no aliases, start an array */
+ if (!is_array($config['aliases']['alias'])) {
+ $config['aliases']['alias'] = array();
+ }
+
+ $a_aliases = &$config['aliases']['alias'];
+
+ /* Try to get the ID if the alias already exists */
+ $id = easyrule_block_alias_getid($int);
+ if ($id === false) {
+ unset($id);
+ }
+
+ $alias = array();
+
+ if (is_subnet($host)) {
+ list($host, $mask) = explode("/", $host);
+ } elseif (is_specialnet($host)) {
+ $mask = 0;
+ } elseif (is_ipaddrv6($host)) {
+ $mask = 128;
+ } else {
+ $mask = 32;
+ }
+
+ if (isset($id) && $a_aliases[$id]) {
+
+ // Catch case when the list is empty
+ if (empty($a_aliases[$id]['address'])) {
+ $a_address = array();
+ $a_detail = array();
+ } else {
+ $a_address = explode(" ", $a_aliases[$id]['address']);
+
+ /* Make sure this IP isn't already in the list. */
+ if (in_array($host.'/'.$mask, $a_address)) {
+ return true;
+ }
+ $a_detail = explode("||", $a_aliases[$id]['detail']);
+ }
+
+ /* Since the alias already exists, just add to it. */
+ $alias['name'] = $a_aliases[$id]['name'];
+ $alias['type'] = $a_aliases[$id]['type'];
+ $alias['descr'] = $a_aliases[$id]['descr'];
+
+ $a_address[] = $host.'/'.$mask;
+ $a_detail[] = gettext('Entry added') . ' ' . date('r');
+
+ $alias['address'] = join(" ", $a_address);
+ $alias['detail'] = join("||", $a_detail);
+
+ } else {
+ /* Create a new alias with all the proper information */
+ $alias['name'] = $blockaliasname . strtoupper($int);
+ $alias['type'] = 'network';
+ $alias['descr'] = gettext("Hosts blocked from Firewall Log view");
+
+ $alias['address'] = $host . '/' . $mask;
+ $alias['detail'] = gettext('Entry added') . ' ' . date('r') . '||';
+ }
+
+ /* Replace the old alias if needed, otherwise tack it on the end */
+ if (isset($id) && $a_aliases[$id]) {
+ $a_aliases[$id] = $alias;
+ } else {
+ $a_aliases[] = $alias;
+ }
+
+ // Sort list
+ $a_aliases = msort($a_aliases, "name");
+
+ return true;
+}
+
+function easyrule_block_host_add($host, $int = 'wan', $ipproto = "inet") {
+ global $retval;
+ /* Bail if the supplied host is not a valid IP address */
+ $host = trim($host, "[]");
+ if (!is_ipaddr($host) && !is_subnet($host)) {
+ return false;
+ }
+
+ /* Flag whether or not we need to reload the filter */
+ $dirty = false;
+
+ /* Attempt to add this host to the alias */
+ if (easyrule_block_alias_add($host, $int)) {
+ $dirty = true;
+ } else {
+ /* Couldn't add the alias, or adding the host failed. */
+ return false;
+ }
+
+ /* Attempt to add the firewall rule if it doesn't exist.
+ * Failing to add the rule isn't necessarily an error, it may
+ * have been modified by the user in some way. Adding to the
+ * Alias is what's important.
+ */
+ if (!easyrule_block_rule_exists($int, $ipproto)) {
+ if (easyrule_block_rule_create($int, $ipproto)) {
+ $dirty = true;
+ } else {
+ return false;
+ }
+ }
+
+ /* If needed, write the config and reload the filter */
+ if ($dirty) {
+ write_config();
+ $retval = filter_configure();
+ if (!empty($_SERVER['DOCUMENT_ROOT'])) {
+ header("Location: firewall_aliases.php");
+ exit;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
+
+function easyrule_pass_rule_add($int, $proto, $srchost, $dsthost, $dstport, $ipproto) {
+ global $config;
+
+ /* No rules, start a new array */
+ if (!is_array($config['filter']['rule'])) {
+ $config['filter']['rule'] = array();
+ }
+
+ filter_rules_sort();
+ $a_filter = &$config['filter']['rule'];
+
+ /* Make up a new rule */
+ $filterent = array();
+ $filterent['type'] = 'pass';
+ $filterent['interface'] = $int;
+ $filterent['ipprotocol'] = $ipproto;
+ $filterent['descr'] = gettext("Easy Rule: Passed from Firewall Log View");
+
+ if ($proto != "any") {
+ $filterent['protocol'] = $proto;
+ } else {
+ unset($filterent['protocol']);
+ }
+
+ /* Default to only allow echo requests, since that's what most people want and
+ * it should be a safe choice. */
+ if ($proto == "icmp") {
+ $filterent['icmptype'] = 'echoreq';
+ }
+
+ if ((strtolower($proto) == "icmp6") || (strtolower($proto) == "icmpv6")) {
+ $filterent['protocol'] = "icmp";
+ }
+
+ if (is_subnet($srchost)) {
+ list($srchost, $srcmask) = explode("/", $srchost);
+ } elseif (is_specialnet($srchost)) {
+ $srcmask = 0;
+ } elseif (is_ipaddrv6($srchost)) {
+ $srcmask = 128;
+ } else {
+ $srcmask = 32;
+ }
+
+ if (is_subnet($dsthost)) {
+ list($dsthost, $dstmask) = explode("/", $dsthost);
+ } elseif (is_specialnet($dsthost)) {
+ $dstmask = 0;
+ } elseif (is_ipaddrv6($dsthost)) {
+ $dstmask = 128;
+ } else {
+ $dstmask = 32;
+ }
+
+ pconfig_to_address($filterent['source'], $srchost, $srcmask);
+ pconfig_to_address($filterent['destination'], $dsthost, $dstmask, '', $dstport, $dstport);
+
+ $filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
+ $a_filter[] = $filterent;
+
+ write_config($filterent['descr']);
+ $retval = filter_configure();
+ if (!empty($_SERVER['DOCUMENT_ROOT'])) {
+ header("Location: firewall_rules.php?if={$int}");
+ exit;
+ } else {
+ return true;
+ }
+}
+
+function easyrule_parse_block($int, $src, $ipproto = "inet") {
+ if (!empty($src) && !empty($int)) {
+ $src = trim($src, "[]");
+ if (!is_ipaddr($src) && !is_subnet($src)) {
+ return gettext("Tried to block invalid IP:") . ' ' . htmlspecialchars($src);
+ }
+ $int = easyrule_find_rule_interface($int);
+ if ($int === false) {
+ return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
+ }
+ if (easyrule_block_host_add($src, $int, $ipproto)) {
+ return gettext("Host added successfully");
+ } else {
+ return gettext("Failed to create block rule, alias, or add host.");
+ }
+ } else {
+ return gettext("Tried to block but had no host IP or interface");
+ }
+ return gettext("Unknown block error.");
+}
+
+function easyrule_parse_unblock($int, $host, $ipproto = "inet") {
+ global $blockaliasname, $config;
+
+ if (!empty($host) && !empty($int)) {
+ $host = trim($host, "[]");
+ if (!is_ipaddr($host) && !is_subnet($host)) {
+ return gettext("Tried to unblock invalid IP:") . ' ' . htmlspecialchars($host);
+ }
+ $real_int = easyrule_find_rule_interface($int);
+ if ($real_int === false) {
+ return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
+ }
+
+ /* Try to get the ID - will fail if there are no rules/alias on this interface */
+ $id = easyrule_block_alias_getid($real_int);
+ if ($id === false || !$config['aliases']['alias'][$id]) {
+ return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
+ }
+
+ $alias = &$config['aliases']['alias'][$id];
+
+ if (is_subnet($host)) {
+ list($host, $mask) = explode("/", $host);
+ } elseif (is_specialnet($host)) {
+ $mask = 0;
+ } elseif (is_ipaddrv6($host)) {
+ $mask = 128;
+ } else {
+ $mask = 32;
+ }
+
+ // Create the expected string representation
+ $unblock = $host.'/'.$mask;
+
+ $a_address = explode(" ", $config['aliases']['alias'][$id]['address']);
+ $a_detail = explode("||", $config['aliases']['alias'][$id]['detail']);
+
+ if (($key = array_search($unblock, $a_address)) !== false) {
+ unset($a_address[$key]);
+ unset($a_detail[$key]);
+ // Write back the result to the config array
+ $config['aliases']['alias'][$id]['address'] = join(" ", $a_address);
+ $config['aliases']['alias'][$id]['detail'] = join("||", $a_detail);
+
+ // Update config
+ write_config();
+ $retval = filter_configure();
+ if (!empty($_SERVER['DOCUMENT_ROOT'])) {
+ header("Location: firewall_aliases.php");
+ exit;
+ } else {
+ return gettext("Host unblocked successfully");
+ }
+ } else {
+ return gettext("Host ist not on block list: " . $host);
+ }
+ }
+
+ return gettext("Tried to unblock but had no host IP or interface");
+
+}
+
+function easyrule_parse_getblock($int = 'wan', $sep = "\n") {
+ global $blockaliasname, $config;
+
+ $real_int = easyrule_find_rule_interface($int);
+ if ($real_int === false) {
+ return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
+ }
+
+ /* Try to get the ID - will fail if there are no rules/alias on this interface */
+ $id = easyrule_block_alias_getid($real_int);
+
+ if ($id === false || !$config['aliases']['alias'][$id] || empty($config['aliases']['alias'][$id]['address'])) {
+ return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
+ }
+ return join($sep, explode(" ", $config['aliases']['alias'][$id]['address']));
+
+}
+
+function easyrule_parse_pass($int, $proto, $src, $dst, $dstport = 0, $ipproto = "inet") {
+ /* Check for valid int, srchost, dsthost, dstport, and proto */
+ global $protocols_with_ports;
+ $src = trim($src, "[]");
+ $dst = trim($dst, "[]");
+
+ if (!empty($int) && !empty($proto) && !empty($src) && !empty($dst)) {
+ $int = easyrule_find_rule_interface($int);
+ if ($int === false) {
+ return gettext("Invalid interface for pass rule:") . ' ' . htmlspecialchars($int);
+ }
+ if (getprotobyname($proto) == -1) {
+ return gettext("Invalid protocol for pass rule:") . ' ' . htmlspecialchars($proto);
+ }
+ if (!is_ipaddr($src) && !is_subnet($src) && !is_ipaddroralias($src) && !is_specialnet($src)) {
+ return gettext("Tried to pass invalid source IP:") . ' ' . htmlspecialchars($src);
+ }
+ if (!is_ipaddr($dst) && !is_subnet($dst) && !is_ipaddroralias($dst) && !is_specialnet($dst)) {
+ return gettext("Tried to pass invalid destination IP:") . ' ' . htmlspecialchars($dst);
+ }
+ if (in_array($proto, $protocols_with_ports)) {
+ if (empty($dstport)) {
+ return gettext("Missing destination port:") . ' ' . htmlspecialchars($dstport);
+ }
+ if (!is_port($dstport) && ($dstport != "any")) {
+ return gettext("Tried to pass invalid destination port:") . ' ' . htmlspecialchars($dstport);
+ }
+ } else {
+ $dstport = 0;
+ }
+ /* Should have valid input... */
+ if (easyrule_pass_rule_add($int, $proto, $src, $dst, $dstport, $ipproto)) {
+ return gettext("Successfully added pass rule!");
+ } else {
+ return gettext("Failed to add pass rule.");
+ }
+ } else {
+ return gettext("Missing parameters for pass rule.");
+ }
+ return gettext("Unknown pass error.");
+}
+
+?>
diff --git a/src/etc/inc/filter.inc b/src/etc/inc/filter.inc
new file mode 100644
index 0000000..36bbe2b
--- /dev/null
+++ b/src/etc/inc/filter.inc
@@ -0,0 +1,4228 @@
+<?php
+/* $Id$ */
+/*
+ filter.inc
+ Copyright (C) 2004-2006 Scott Ullrich
+ Copyright (C) 2005 Bill Marquette
+ Copyright (C) 2006 Peter Allgeyer
+ Copyright (C) 2008-2010 Ermal Luçi
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /sbin/kldload /usr/sbin/tcpdump /sbin/pfctl /bin/rm
+ pfSense_BUILDER_BINARIES: /usr/sbin/inetd
+ pfSense_MODULE: filter
+*/
+
+
+/* holds the items that will be executed *AFTER* the filter is fully loaded */
+$after_filter_configure_run = array();
+
+/* For installing cron job of schedules */
+$time_based_rules = false;
+
+/* Used to hold the interface list that will be used on ruleset creation. */
+$FilterIflist = array();
+
+/* Create a global array to avoid errors on rulesets. */
+$GatewaysList = array();
+
+/* Used for the hostname dns resolver */
+$filterdns = array();
+
+/* Used for aliases and interface macros */
+$aliases = "";
+
+/* ICMP v4 types */
+$icmptypes = array(
+ "" => gettext("any"),
+ "echoreq" => gettext("Echo request"),
+ "echorep" => gettext("Echo reply"),
+ "unreach" => gettext("Destination unreachable"),
+ "squench" => gettext("Source quench"),
+ "redir" => gettext("Redirect"),
+ "althost" => gettext("Alternate Host"),
+ "routeradv" => gettext("Router advertisement"),
+ "routersol" => gettext("Router solicitation"),
+ "timex" => gettext("Time exceeded"),
+ "paramprob" => gettext("Invalid IP header"),
+ "timereq" => gettext("Timestamp"),
+ "timerep" => gettext("Timestamp reply"),
+ "inforeq" => gettext("Information request"),
+ "inforep" => gettext("Information reply"),
+ "maskreq" => gettext("Address mask request"),
+ "maskrep" => gettext("Address mask reply"),
+ "trace" => gettext("Traceroute"),
+ "dataconv" => gettext("Datagram conversion error"),
+ "mobredir" => gettext("Mobile host redirect"),
+ "ipv6-where" => gettext("IPv6 where-are-you"),
+ "ipv6-here" => gettext("IPv6 I-am-here"),
+ "mobregreq" => gettext("Mobile registration request"),
+ "mobregrep" => gettext("Mobile registration reply"),
+ "skip" => gettext("SKIP"),
+ "photuris" => gettext("Photuris")
+);
+
+/* ICMP v6 types */
+$icmp6types = array(
+ "" => gettext("any"),
+ "unreach" => gettext("Destination unreachable"),
+ "toobig" => gettext("Packet too big"),
+ "timex" => gettext("Time exceeded"),
+ "paramprob" => gettext("Parameter problem"),
+ "echoreq" => gettext("Echo request"),
+ "echorep" => gettext("Echo reply"),
+ "groupqry" => gettext("Group membership query"),
+ "listqry" => gettext("Multicast listener query"),
+ "grouprep" => gettext("Group membership report"),
+ "listenrep" => gettext("Multicast listener report"),
+ "groupterm" => gettext("Group membership termination"),
+ "listendone" => gettext("Multicast listener done"),
+ "routersol" => gettext("Router solicitation"),
+ "routeradv" => gettext("Router advertisement"),
+ "neighbrsol" => gettext("Neighbor solicitation"),
+ "neighbradv" => gettext("Neighbor advertisement"),
+ "redir" => gettext("Redirect"),
+ "routrrenum" => gettext("Router renumbering"),
+ "wrureq" => gettext("Who are you request"),
+ "wrurep" => gettext("Who are you reply"),
+ "fqdnreq" => gettext("FQDN query"),
+ "fqdnrep" => gettext("FQDN reply"),
+ "niqry" => gettext("Node information request"),
+ "nirep" => gettext("Node information reply"),
+ "mtraceresp" => gettext("mtrace resp"),
+ "mtrace" => gettext("mtrace messages")
+);
+
+global $tracker;
+global $negate_tracker;
+$tracker = 1000000000;
+$negate_tracker = 10000000;
+
+function filter_rule_tracker($tracker) {
+ global $tracker;
+
+ return (++$tracker);
+}
+
+function filter_negaterule_tracker() {
+ global $negate_tracker;
+
+ ++$negate_tracker;
+ return "tracker {$negate_tracker} ";
+}
+
+function fix_rule_label($descr) {
+ $descr = str_replace('"', '', $descr);
+ if (strlen($descr) > 63) {
+ return substr($descr, 0, 60) . "...";
+ } else {
+ return $descr;
+ }
+}
+
+function is_bogonsv6_used() {
+ global $config, $g;
+ # Only use bogonsv6 table if IPv6 Allow is on, and at least 1 enabled interface also has "blockbogons" enabled.
+ $usebogonsv6 = false;
+ if (isset($config['system']['ipv6allow'])) {
+ foreach ($config['interfaces'] as $ifacedata) {
+ if (isset($ifacedata['enable']) && isset($ifacedata['blockbogons'])) {
+ $usebogonsv6 = true;
+ break;
+ }
+ }
+ }
+ return $usebogonsv6;
+}
+
+function filter_pflog_start($kill_first = false) {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_pflog_start() being called $mt\n";
+ }
+ if ((!file_exists("{$g['varrun_path']}/filterlog.pid")) ||
+ (!isvalidpid("{$g['varrun_path']}/filterlog.pid"))) {
+ mwexec("/usr/local/sbin/filterlog -i pflog0 -p {$g['varrun_path']}/filterlog.pid");
+ }
+}
+
+/* reload filter async */
+function filter_configure() {
+ global $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_configure() being called $mt\n";
+ }
+
+ /*
+ * NOTE: Check here for bootup status since this should not be triggered during bootup.
+ * The reason is that rc.bootup calls filter_configure_sync directly which does this too.
+ */
+ if (!platform_booting()) {
+ send_event("filter reload");
+ }
+}
+
+function filter_delete_states_for_down_gateways() {
+ global $config, $GatewaysList;
+
+ if (isset($config['system']['kill_states'])) {
+ return;
+ }
+
+ $any_gateway_down = false;
+ $a_gateways = return_gateways_status();
+ if (is_array($GatewaysList)) {
+ foreach ($GatewaysList as $gwname => $gateway) {
+ if (empty($gateway['monitor'])) {
+ continue;
+ }
+ if (!is_ipaddr($gateway['monitor'])) {
+ continue;
+ }
+ if (strstr($gateway['monitor'], "127.0.0.")) {
+ continue;
+ }
+ if (empty($a_gateways[$gateway['monitor']])) {
+ continue;
+ }
+ $gwstatus =& $a_gateways[$gateway['monitor']];
+ if (strstr($gwstatus['status'], "down")) {
+ $any_gateway_down = true;
+ break;
+ }
+ }
+ }
+ if ($any_gateway_down == true) {
+ mwexec("/sbin/pfctl -Fs");
+ }
+}
+
+/* reload filter sync */
+function filter_configure_sync($delete_states_if_needed = true) {
+ global $config, $g, $after_filter_configure_run, $FilterIflist;
+ global $time_based_rules, $filterdns, $aliases, $dummynet_name_list;
+
+ /* Use filter lock to not allow concurrent filter reloads during this run. */
+ $filterlck = lock('filter', LOCK_EX);
+
+ filter_pflog_start();
+ update_filter_reload_status(gettext("Initializing"));
+
+ /* invalidate interface cache */
+ get_interface_arr(true);
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_configure_sync() being called $mt\n";
+ }
+ /* Get interface list to work with. */
+ filter_generate_optcfg_array();
+ if (platform_booting() == true) {
+ echo gettext("Configuring firewall");
+ }
+
+ /* generate aliases */
+ if (platform_booting() == true) {
+ echo ".";
+ }
+ update_filter_reload_status(gettext("Creating aliases"));
+ $aliases = filter_generate_aliases();
+ $gateways = filter_generate_gateways();
+ if (platform_booting() == true) {
+ echo ".";
+ }
+ update_filter_reload_status(gettext("Generating Limiter rules"));
+ $dummynet_rules = filter_generate_dummynet_rules();
+ $dummynet_name_list = get_unique_dnqueue_list();
+ update_filter_reload_status(gettext("Generating NAT rules"));
+ /* generate nat rules */
+ $natrules = filter_nat_rules_generate();
+ if (platform_booting() == true) {
+ echo ".";
+ }
+ update_filter_reload_status(gettext("Generating filter rules"));
+ /* generate pfctl rules */
+ $pfrules = filter_rules_generate();
+ /* generate altq, limiter */
+ if (platform_booting() == true) {
+ echo ".";
+ }
+ update_filter_reload_status(gettext("Generating ALTQ queues"));
+ $altq_queues = filter_generate_altq_queues();
+ update_filter_reload_status(gettext("Generating Layer7 rules"));
+ generate_layer7_files();
+ if (platform_booting() == true) {
+ echo ".";
+ }
+ update_filter_reload_status(gettext("Loading filter rules"));
+ /* enable pf if we need to, otherwise disable */
+ if (!isset ($config['system']['disablefilter'])) {
+ mwexec("/sbin/pfctl -e", true);
+ } else {
+ mwexec("/sbin/pfctl -d", true);
+ unlink_if_exists("{$g['tmp_path']}/filter_loading");
+ update_filter_reload_status(gettext("Filter is disabled. Not loading rules."));
+ if (platform_booting() == true) {
+ echo gettext("done.") . "\n";
+ }
+ unlock($filterlck);
+ return;
+ }
+
+ $limitrules = "";
+ /* User defined maximum table entries in Advanced menu. */
+ if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries'])) {
+ $limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
+ }
+
+ if ($config['system']['optimization'] <> "") {
+ $limitrules .= "set optimization {$config['system']['optimization']}\n";
+ if ($config['system']['optimization'] == "conservative") {
+ $limitrules .= "set timeout { udp.first 300, udp.single 150, udp.multiple 900 }\n";
+ }
+ } else {
+ $limitrules .= "set optimization normal\n";
+ }
+
+ $timeoutlist = "";
+ if (isset($config['system']['tcpfirsttimeout']) && is_numericint($config['system']['tcpfirsttimeout'])) {
+ $timeoutlist .= " tcp.first {$config['system']['tcpfirsttimeout']} ";
+ }
+ if (isset($config['system']['tcpopeningtimeout']) && is_numericint($config['system']['tcpopeningtimeout'])) {
+ $timeoutlist .= " tcp.opening {$config['system']['tcpopeningtimeout']} ";
+ }
+ if (isset($config['system']['tcpestablishedtimeout']) && is_numericint($config['system']['tcpestablishedtimeout'])) {
+ $timeoutlist .= " tcp.established {$config['system']['tcpestablishedtimeout']} ";
+ }
+ if (isset($config['system']['tcpclosingtimeout']) && is_numericint($config['system']['tcpclosingtimeout'])) {
+ $timeoutlist .= " tcp.closing {$config['system']['tcpclosingtimeout']} ";
+ }
+ if (isset($config['system']['tcpfinwaittimeout']) && is_numericint($config['system']['tcpfinwaittimeout'])) {
+ $timeoutlist .= " tcp.finwait {$config['system']['tcpfinwaittimeout']} ";
+ }
+ if (isset($config['system']['tcpclosedtimeout']) && is_numericint($config['system']['tcpclosedtimeout'])) {
+ $timeoutlist .= " tcp.closed {$config['system']['tcpclosedtimeout']} ";
+ }
+ if (isset($config['system']['udpfirsttimeout']) && is_numericint($config['system']['udpfirsttimeout'])) {
+ $timeoutlist .= " udp.first {$config['system']['udpfirsttimeout']} ";
+ }
+ if (isset($config['system']['udpsingletimeout']) && is_numericint($config['system']['udpsingletimeout'])) {
+ $timeoutlist .= " udp.single {$config['system']['udpsingletimeout']} ";
+ }
+ if (isset($config['system']['udpmultipletimeout']) && is_numericint($config['system']['udpmultipletimeout'])) {
+ $timeoutlist .= " udp.multiple {$config['system']['udpmultipletimeout']} ";
+ }
+ if (isset($config['system']['icmpfirsttimeout']) && is_numericint($config['system']['icmpfirsttimeout'])) {
+ $timeoutlist .= " icmp.first {$config['system']['icmpfirsttimeout']} ";
+ }
+ if (isset($config['system']['icmperrortimeout']) && is_numericint($config['system']['icmperrortimeout'])) {
+ $timeoutlist .= " icmp.error {$config['system']['icmperrortimeout']} ";
+ }
+ if (isset($config['system']['otherfirsttimeout']) && is_numericint($config['system']['otherfirsttimeout'])) {
+ $timeoutlist .= " other.first {$config['system']['otherfirsttimeout']} ";
+ }
+ if (isset($config['system']['othersingletimeout']) && is_numericint($config['system']['othersingletimeout'])) {
+ $timeoutlist .= " other.single {$config['system']['othersingletimeout']} ";
+ }
+ if (isset($config['system']['othermultipletimeout']) && is_numericint($config['system']['othermultipletimeout'])) {
+ $timeoutlist .= " other.multiple {$config['system']['othermultipletimeout']} ";
+ }
+
+ if ($timeoutlist <> "") {
+ $limitrules .= "set timeout { $timeoutlist }\n";
+ }
+
+ if (!empty($config['system']['adaptivestart']) && !empty($config['system']['adaptiveend'])) {
+ $limitrules .= "set timeout { adaptive.start {$config['system']['adaptivestart']}, adaptive.end {$config['system']['adaptiveend']} }\n";
+ }
+
+ if ($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates'])) {
+ /* User defined maximum states in Advanced menu. */
+ $limitrules .= "set limit states {$config['system']['maximumstates']}\n";
+ $limitrules .= "set limit src-nodes {$config['system']['maximumstates']}\n";
+ } else {
+ $max_states = pfsense_default_state_size();
+ $limitrules .= "set limit states {$max_states}\n";
+ $limitrules .= "set limit src-nodes {$max_states}\n";
+ }
+
+ /* Frag limit. pf default is 5000 */
+ if ($config['system']['maximumfrags'] <> "" && is_numeric($config['system']['maximumfrags'])) {
+ $limitrules .= "set limit frags {$config['system']['maximumfrags']}\n";
+ }
+
+ if (isset($config['system']['lb_use_sticky']) && is_numeric($config['system']['srctrack']) && ($config['system']['srctrack'] > 0)) {
+ $limitrules .= "set timeout src.track {$config['system']['srctrack']}\n";
+ }
+
+ $rules = "";
+ $rules = "{$limitrules}\n";
+ $rules .= "{$aliases} \n";
+ $rules .= "{$gateways} \n";
+ update_filter_reload_status(gettext("Setting up logging information"));
+ $rules .= filter_setup_logging_interfaces();
+ $rules .= "\n";
+ $rules .= "set skip on pfsync0\n";
+ $rules .= "\n";
+ update_filter_reload_status(gettext("Setting up SCRUB information"));
+ $rules .= filter_generate_scrubing();
+ $rules .= "\n";
+ $rules .= "{$altq_queues}\n";
+ $rules .= "{$natrules}\n";
+ $rules .= "{$pfrules}\n";
+ $rules .= discover_pkg_rules("filter");
+
+ unset($aliases, $gateways, $altq_queues, $natrules, $pfrules);
+
+ // Copy rules.debug to rules.debug.old
+ if (file_exists("{$g['tmp_path']}/rules.debug")) {
+ @copy("{$g['tmp_path']}/rules.debug", "{$g['tmp_path']}/rules.debug.old");
+ }
+
+ if (!@file_put_contents("{$g['tmp_path']}/rules.debug", $rules, LOCK_EX)) {
+ log_error("WARNING: Could not write new rules!");
+ unlock($filterlck);
+ return;
+ }
+
+ @file_put_contents("{$g['tmp_path']}/rules.limits", $limitrules);
+ mwexec("/sbin/pfctl -Of {$g['tmp_path']}/rules.limits");
+ unset($rules, $limitrules);
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "pfctl being called at $mt\n";
+ }
+ unset($rules_loading, $rules_error);
+ $_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug 2>&1", $rules_error, $rules_loading);
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "pfctl done at $mt\n";
+ }
+ /*
+ * check for a error while loading the rules file. if an error has occurred
+ * then output the contents of the error to the caller
+ */
+ if ($rules_loading <> 0) {
+ $saved_line_error = $rules_error[0];
+ $line_error = explode(":", $rules_error[0]);
+ $line_number = $line_error[1];
+ $line_split = file("{$g['tmp_path']}/rules.debug");
+ if (is_array($line_split)) {
+ $line_error = sprintf(gettext('The line in question reads [%1$d]: %2$s'), $line_number, $line_split[$line_number-1]);
+ }
+ unset($line_split);
+
+ /* Brutal ugly hack but required -- PF is stuck, unwedge */
+ if (strstr("$rules_error[0]", "busy")) {
+ exec("/sbin/pfctl -d; /sbin/pfctl -e; /sbin/pfctl -f {$g['tmp_path']}/rules.debug");
+ $error_msg = gettext("PF was wedged/busy and has been reset.");
+ file_notice("pf_busy", $error_msg, "pf_busy", "");
+ } else {
+ $_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug.old 2>&1");
+ }
+ unset($rules_loading, $rules_error);
+
+ if ($line_error and $line_number) {
+ file_notice("filter_load", sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error), "Filter Reload", "");
+ update_filter_reload_status(sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error));
+ unlock($filterlck);
+ return;
+ }
+ }
+
+ # If we are not using bogonsv6 then we can remove any bogonsv6 table from the running pf (if the table is not there, the kill is still fine).
+ if (!is_bogonsv6_used()) {
+ $_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
+ }
+
+ update_filter_reload_status(gettext("Starting up layer7 daemon"));
+ layer7_start_l7daemon();
+
+ if (!platform_booting()) {
+ if (!empty($filterdns)) {
+ @file_put_contents("{$g['varetc_path']}/filterdns.conf", implode("", $filterdns));
+ unset($filterdns);
+ if (isvalidpid("{$g['varrun_path']}/filterdns.pid")) {
+ sigkillbypid("{$g['varrun_path']}/filterdns.pid", "HUP");
+ } else {
+ /*
+ * FilterDNS has three debugging levels. The default chosen is 1.
+ * Available are level 2 and greater then 2.
+ */
+ if (isset($config['system']['aliasesresolveinterval']) && is_numeric($config['system']['aliasesresolveinterval'])) {
+ $resolve_interval = $config['system']['aliasesresolveinterval'];
+ } else {
+ $resolve_interval = 300;
+ }
+ mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns.pid -i {$resolve_interval} -c {$g['varetc_path']}/filterdns.conf -d 1");
+ }
+ } else {
+ killbypid("{$g['varrun_path']}/filterdns.pid");
+ @unlink("{$g['varrun_path']}/filterdns.pid");
+ }
+ }
+
+ /* run items scheduled for after filter configure run */
+ $fda = fopen("{$g['tmp_path']}/commands.txt", "w");
+ if ($fda) {
+ if ($after_filter_configure_run) {
+ foreach ($after_filter_configure_run as $afcr) {
+ fwrite($fda, $afcr . "\n");
+ }
+ unset($after_filter_configure_run);
+ }
+
+ /*
+ * we need a way to let a user run a shell cmd after each
+ * filter_configure() call. run this xml command after
+ * each change.
+ */
+ if ($config['system']['afterfilterchangeshellcmd'] <> "") {
+ fwrite($fda, $config['system']['afterfilterchangeshellcmd'] . "\n");
+ }
+
+ fclose($fda);
+ }
+
+ if (file_exists("{$g['tmp_path']}/commands.txt")) {
+ mwexec("sh {$g['tmp_path']}/commands.txt &");
+ unlink("{$g['tmp_path']}/commands.txt");
+ }
+
+ /* if time based rules are enabled then swap in the set */
+ if ($time_based_rules == true) {
+ filter_tdr_install_cron(true);
+ } else {
+ filter_tdr_install_cron(false);
+ }
+
+ if (platform_booting() == true) {
+ echo ".";
+ }
+
+ if ($delete_states_if_needed) {
+ update_filter_reload_status(gettext("Processing down interface states"));
+ filter_delete_states_for_down_gateways();
+ }
+
+ update_filter_reload_status(gettext("Running plugins"));
+
+ if (is_dir("/usr/local/pkg/pf/")) {
+ /* process packager manager custom rules */
+ update_filter_reload_status(gettext("Running plugins (pf)"));
+ run_plugins("/usr/local/pkg/pf/");
+ update_filter_reload_status(gettext("Plugins completed."));
+ }
+
+ update_filter_reload_status(gettext("Done"));
+ if (platform_booting() == true) {
+ echo gettext("done.") . "\n";
+ }
+
+ unlock($filterlck);
+ return 0;
+}
+
+function filter_generate_scrubing() {
+ global $config, $FilterIflist;
+ $scrubrules = "";
+
+ if (isset($config['system']['maxmss_enable'])) {
+ $maxmss = 1400;
+ if (!empty($config['system']['maxmss'])) {
+ $maxmss = $config['system']['maxmss'];
+ }
+
+ $scrubrules .= "scrub from any to <vpn_networks> max-mss {$maxmss}\n";
+ $scrubrules .= "scrub from <vpn_networks> to any max-mss {$maxmss}\n";
+ }
+ /* disable scrub option */
+ foreach ($FilterIflist as $scrubif => $scrubcfg) {
+ if (isset($scrubcfg['virtual']) || empty($scrubcfg['descr'])) {
+ continue;
+ }
+ /* set up MSS clamping */
+ if (($scrubcfg['mss'] <> "") &&
+ (is_numeric($scrubcfg['mss'])) &&
+ ($scrubcfg['if'] != "pppoe") &&
+ ($scrubcfg['if'] != "pptp") &&
+ ($scrubif['if'] != "l2tp")) {
+ $mssclamp = "max-mss " . (intval($scrubcfg['mss'] - 40));
+ } else {
+ $mssclamp = "";
+ }
+ /* configure no-df for linux nfs and others */
+ if ($config['system']['scrubnodf']) {
+ $scrubnodf = "no-df";
+ } else {
+ $scrubnodf = "";
+ }
+ if ($config['system']['scrubrnid']) {
+ $scrubrnid = "random-id";
+ } else {
+ $scrubrnid = "";
+ }
+ if (!isset($config['system']['disablescrub'])) {
+ $scrubrules .= "scrub on \${$scrubcfg['descr']} all {$scrubnodf} {$scrubrnid} {$mssclamp} fragment reassemble\n"; // reassemble all directions
+ } else if (!empty($mssclamp)) {
+ $scrubrules .= "scrub on \${$scrubcfg['descr']} {$mssclamp}\n";
+ }
+ }
+ return $scrubrules;
+}
+
+function filter_generate_nested_alias($name, $alias, &$aliasnesting, &$aliasaddrnesting) {
+ global $aliastable, $filterdns;
+
+ $addresses = explode(" ", $alias);
+ $use_filterdns = false;
+ $finallist = "";
+ $builtlist = "";
+ $urltable_nesting = "";
+ $aliasnesting[$name] = $name;
+ $alias_type = alias_get_type($name);
+ foreach ($addresses as $address) {
+ if (empty($address)) {
+ continue;
+ }
+ $linelength = strlen($builtlist);
+ $tmpline = "";
+ if (is_alias($address)) {
+ if (alias_get_type($address) == 'urltable') {
+ // Feature#1603. For this type of alias we do not need to recursively call filter_generate_nested_alias. Just load IPs from the file.
+ $urltable_nesting = alias_expand_urltable($address);
+ if (!empty($urltable_nesting)) {
+ $urlfile_as_arr = file($urltable_nesting);
+ foreach ($urlfile_as_arr as $line) {
+ $address= rtrim($line);
+ if ((strlen($tmpline) + $linelength) > 4036) {
+ $finallist .= "{$tmpline} \\\n";
+ $tmpline = "";
+ }
+ $tmpline .= " {$address}";
+ }
+ }
+ }
+ /* We already expanded this alias so there is no necessity to do it again. */
+ else if (!isset($aliasnesting[$address])) {
+ $tmpline = filter_generate_nested_alias($name, $aliastable[$address], $aliasnesting, $aliasaddrnesting);
+ }
+ } else if (!isset($aliasaddrnesting[$address])) {
+ if (!is_ipaddr($address) && !is_subnet($address) && !((($alias_type == 'port') || ($alias_type == 'url_ports')) && (is_port($address) || is_portrange($address))) && is_hostname($address)) {
+ if (!isset($filterdns["{$address}{$name}"])) {
+ $use_filterdns = true;
+ $filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
+ }
+ continue;
+ }
+ $aliasaddrnesting[$address] = $address;
+ $tmpline = " {$address}";
+ }
+ if ((strlen($tmpline)+ $linelength) > 4036) {
+ $finallist .= "{$builtlist} \\\n";
+ $builtlist = "";
+ }
+ if (!empty($tmpline)) {
+ $builtlist .= " {$tmpline}";
+ }
+ }
+ $finallist .= $builtlist;
+
+ if ($use_filterdns === true && !empty($finallist)) {
+ foreach (explode(" ", $finallist) as $address) {
+ if (empty($address)) {
+ continue;
+ }
+ if ((is_ipaddr($address) || is_subnet($address)) && !isset($filterdns["{$address}{$name}"])) {
+ $filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
+ }
+ }
+ $finallist = '';
+ }
+
+ return $finallist;
+}
+
+function filter_expand_alias($alias_name) {
+ global $config;
+
+ if (isset($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $aliased) {
+ if ($aliased['name'] == $alias_name) {
+ $aliasnesting = array();
+ $aliasaddrnesting = array();
+ return filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
+ }
+ }
+ }
+}
+
+function filter_expand_alias_array($alias_name) {
+ $expansion = filter_expand_alias($alias_name);
+ return explode(" ", preg_replace('/\s+/', ' ', trim($expansion)));
+}
+
+function filter_generate_aliases() {
+ global $config, $FilterIflist, $after_filter_configure_run;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_generate_aliases() being called $mt\n";
+ }
+
+ $alias = "#System aliases\n ";
+ $aliases = "loopback = \"{ lo0 }\"\n";
+
+ foreach ($FilterIflist as $if => $ifcfg) {
+ if (is_array($ifcfg[0])) {
+ if ($ifcfg[0]['if'] == 'pppoe') {
+ $aliases .= "{$ifcfg[0]['descr']} = \"{ {$ifcfg[0]['if']}";
+ $aliases .= " }\"\n";
+ }
+ } elseif (!empty($ifcfg['descr']) && !empty($ifcfg['if'])) {
+ if ($ifcfg['type6'] == '6rd') {
+ $aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
+ } else if ($ifcfg['type6'] == '6to4') {
+ $aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
+ } else {
+ $aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']}";
+
+ if ($ifcfg['type'] == 'pptp') {
+ foreach (get_parent_interface($ifcfg['if']) as $parent_if) {
+ if ($parent_if != $ifcfg['if']) {
+ $aliases .= " {$parent_if}";
+ }
+ }
+ }
+ }
+ $aliases .= " }\"\n";
+ }
+ }
+
+ $aliases .= "\n#SSH Lockout Table\n";
+ $aliases .= "table <sshlockout> persist\n";
+ $aliases .= "table <webConfiguratorlockout> persist\n";
+
+ $aliases .= "#Snort tables\n";
+ $aliases .= "table <snort2c>\n";
+ $aliases .= "table <virusprot>\n";
+ if (!file_exists("/etc/bogons") || !file_exists("/etc/bogonsv6")) {
+ conf_mount_rw();
+ if (!file_exists("/etc/bogons")) {
+ @file_put_contents("/etc/bogons", "");
+ }
+ if (!file_exists("/etc/bogonsv6")) {
+ @file_put_contents("/etc/bogonsv6", "");
+ }
+ conf_mount_ro();
+ }
+ $aliases .= "table <bogons> persist file \"/etc/bogons\"\n";
+ if (is_bogonsv6_used()) {
+ $aliases .= "table <bogonsv6> persist file \"/etc/bogonsv6\"\n";
+ }
+
+ $vpns_list = filter_get_vpns_list();
+ if ($vpns_list) {
+ $aliases .= "table <vpn_networks> { $vpns_list }\n";
+ }
+
+ /* add a Negate_networks table */
+ $aliases .= "table <negate_networks> ";
+ if ($vpns_list) {
+ $aliases .= "{ $vpns_list }";
+ }
+ $aliases .= "\n";
+
+ $aliases .= "\n# User Aliases \n";
+ /* Setup pf groups */
+ if (isset($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $aliased) {
+ $extralias = "";
+ $aliasnesting = array();
+ $aliasaddrnesting = array();
+ if (is_numericint($aliased['name'])) {
+ // skip aliases with numeric-only names. redmine #4289
+ file_notice("Filter_Reload", "Aliases with numeric-only names are not valid. Skipping alias " . $aliased['name']);
+ continue;
+ }
+ $addrlist = filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
+ switch ($aliased['type']) {
+ case "host":
+ case "network":
+ case "url":
+ $tableaddrs = "{$addrlist}{$extralias}";
+ if (empty($tableaddrs)) {
+ $aliases .= "table <{$aliased['name']}> persist\n";
+ if (empty($aliased['address'])) {
+ $after_filter_configure_run[] = "/sbin/pfctl -T flush -t " . escapeshellarg($aliased['name']);
+ }
+ } else {
+ $aliases .= "table <{$aliased['name']}> { {$addrlist}{$extralias} } \n";
+ }
+
+ $aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
+ break;
+ case "openvpn":
+ $openvpncfg = array();
+ if ($config['openvpn']['user']) {
+ /* XXX: Check if we have a correct ip? */
+ foreach ($config['openvpn']['user'] as $openvpn) {
+ $openvpncfg[$openvpn['name']] = $openvpn['ip'];
+ }
+ }
+ $vpn_lines = explode("\n", $addrlist);
+ foreach ($vpn_lines as $vpn_line) {
+ $vpn_address_split = explode(" ", $vpn_line);
+ foreach ($vpn_address_split as $vpnsplit) {
+ if (isset($openvpncfg[$vpnsplit])) {
+ $newaddress .= " ";
+ $newaddress .= $openvpn[$vpnsplit];
+ break;
+ }
+ }
+ }
+ $aliases .= "table <{$aliased['name']}> { {$newaddress}{$extralias} } \n";
+ $aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
+ break;
+ case "urltable":
+ $urlfn = alias_expand_urltable($aliased['name']);
+ if ($urlfn) {
+ $aliases .= "table <{$aliased['name']}> persist file \"{$urlfn}\"\n";
+ $aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
+ }
+ break;
+ case "urltable_ports":
+ // TODO: Change it when pf supports tables with ports
+ $urlfn = alias_expand_urltable($aliased['name']);
+ if ($urlfn) {
+ $aliases .= "{$aliased['name']} = \"{ " . preg_replace("/\n/", " ", file_get_contents($urlfn)) . " }\"\n";
+ }
+ break;
+ case "port":
+ case "url_ports":
+ $aliases .= "{$aliased['name']} = \"{ {$addrlist} }\"\n";
+ break;
+ default:
+ $aliases .= "{$aliased['name']} = \"{ {$aliased['address']}{$extralias} }\"\n";
+ break;
+ }
+ }
+ }
+ $result = "{$alias} \n";
+ $result .= "{$aliases}";
+
+ return $result;
+}
+
+function filter_generate_gateways() {
+ global $config, $g, $GatewaysList;
+
+ $rules = "# Gateways\n";
+
+ update_filter_reload_status(gettext("Creating gateway group item..."));
+
+ /* Lookup Gateways to be used in filter rules once */
+ $GatewaysList = return_gateways_array();
+ $GatewayGroupsList = return_gateway_groups_array();
+
+ if (is_array($GatewaysList)) {
+ foreach ($GatewaysList as $gwname => $gateway) {
+ $int = $gateway['interface'];
+ $gwip = $gateway['gateway'];
+ $route = "";
+ if (!is_ipaddr($gwip)) {
+ $gwip = get_interface_gateway($gateway['friendlyiface']);
+ }
+ if (is_ipaddr($gwip) && !empty($int) && !isset($gateway['force_down'])) {
+ $route = "route-to ( {$int} {$gwip} )";
+ }
+ if (($route === "") && isset($config['system']['skip_rules_gw_down'])) {
+ unset($GatewaysList[$gwname]);
+ } else {
+ $rules .= "GW{$gwname} = \" {$route} \"\n";
+ }
+ }
+ }
+
+ if (is_array($GatewayGroupsList)) {
+ foreach ($GatewayGroupsList as $gateway => $members) {
+ $route = "";
+ /* hey, that's not a group member! */
+ unset($members['ipprotocol']);
+ if (count($members) > 0) {
+ $foundlb = 0;
+ $routeto = "";
+ foreach ($members as $idx => $member) {
+ $int = $member['int'];
+ $gatewayip = $member['gwip'];
+ if (($int <> "") && is_ipaddr($gatewayip)) {
+ if ($g['debug']) {
+ log_error(sprintf(gettext('Setting up route with %1$s on %2$s'), $gatewayip, $int));
+ }
+ if ($member['weight'] > 1) {
+ $routeto .= str_repeat("( {$int} {$gatewayip} ) ", $member['weight']);
+ } else {
+ $routeto .= "( {$int} {$gatewayip} ) ";
+ }
+ $foundlb++;
+ } else {
+ log_error(sprintf(gettext("An error occurred while trying to find the interface got %s . The rule has not been added."), $gatewayip));
+ }
+ }
+ $route = "";
+ if ($foundlb > 0) {
+ $route = " route-to { {$routeto} } ";
+ if ($foundlb > 1) {
+ $route .= " round-robin ";
+ if (isset($config['system']['lb_use_sticky'])) {
+ $route .= " sticky-address ";
+ }
+ }
+ }
+ }
+ if (($route === "") && isset($config['system']['skip_rules_gw_down'])) {
+ unset($GatewayGroupsList[$gateway]);
+ } else {
+ $rules .= "GW{$gateway} = \" {$route} \"\n";
+ }
+ }
+ }
+
+ /* Create a global array to avoid errors on rulesets. */
+ $GatewaysList = $GatewaysList + $GatewayGroupsList;
+
+ $rules .= "\n";
+
+ return $rules;
+}
+
+/* returns space separated list of vpn subnets */
+function filter_get_vpns_list() {
+ global $config;
+
+ $vpns = "";
+ $vpns_arr = array();
+
+ /* ipsec */
+ if (isset($config['ipsec']['enable'])) {
+ if (is_array($config['ipsec']['phase2'])) {
+ foreach ($config['ipsec']['phase2'] as $ph2ent) {
+ if ((!$ph2ent['mobile']) && ($ph2ent['mode'] != 'transport')) {
+ if (!function_exists('ipsec_idinfo_to_cidr')) {
+ require_once("ipsec.inc");
+ }
+ if (!is_array($ph2ent['remoteid'])) {
+ continue;
+ }
+ $ph2ent['remoteid']['mode'] = $ph2ent['mode'];
+ $vpns_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
+ if (!is_subnet($vpns_subnet) || $vpns_subnet == "0.0.0.0/0") {
+ continue;
+ }
+ $vpns_arr[] = $vpns_subnet;
+ }
+ }
+ }
+ }
+
+ /* openvpn */
+ foreach (array('client', 'server') as $type) {
+ if (is_array($config['openvpn']["openvpn-$type"])) {
+ foreach ($config['openvpn']["openvpn-$type"] as $settings) {
+ if (is_array($settings)) {
+ if (!isset($settings['disable'])) {
+ $remote_networks = explode(',', $settings['remote_network']);
+ foreach ($remote_networks as $remote_network) {
+ if (is_subnet($remote_network) && ($remote_network <> "0.0.0.0/0")) {
+ $vpns_arr[] = $remote_network;
+ }
+ }
+ if (is_subnet($settings['tunnel_network']) && $settings['tunnel_network'] <> "0.0.0.0/0") {
+ $vpns_arr[] = $settings['tunnel_network'];
+ }
+ }
+ }
+ }
+ }
+ }
+ /* pppoe */
+ if (is_array($config['pppoes']['pppoe'])) {
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ if ($pppoe['mode'] == "server") {
+ if (is_ipaddr($pppoe['remoteip'])) {
+ $pppoesub = gen_subnet($pppoe['remoteip'], $pppoe['pppoe_subnet']);
+ if (is_subnet($pppoesub)) {
+ $vpns_arr[] = $pppoesub;
+ }
+ }
+ }
+ }
+ }
+
+ if (!empty($vpns_arr)) {
+ $vpns = implode(" ", $vpns_arr);
+ }
+
+ return $vpns;
+}
+
+/* returns space separated list of directly connected networks
+ * optionally returns an array instead, including friendly interface and gateway (if applicable)
+ */
+function filter_get_direct_networks_list($returnsubnetsonly = true) {
+ global $config, $FilterIflist, $GatewaysList;
+ /* build list of directly connected interfaces and networks */
+ $networks = "";
+ $networks_arr = array();
+ if (empty($FilterIflist)) {
+ filter_generate_optcfg_array();
+ }
+ foreach ($FilterIflist as $ifent => $ifcfg) {
+ $subnet = "{$ifcfg['sa']}/{$ifcfg['sn']}";
+ if (is_subnet($subnet)) {
+ if ($returnsubnetsonly) {
+ $networks_arr[] = $subnet;
+ } else {
+ $networks_arr[] = array(
+ 'subnet' => $subnet,
+ 'if' => $ifent,
+ 'ip' => $ifcfg['ip']);
+ }
+ }
+ }
+ foreach (get_configured_ip_aliases_list(true) as $vip) {
+ $subnet = "{$vip['subnet']}/{$vip['subnet_bits']}";
+ if (is_subnet($subnet) && !(is_subnetv4($subnet) && $vip['subnet_bits'] == 32) && !(is_subnetv6($subnet) && $vip['subnet_bits'] == 128)) {
+ if (is_subnetv4($subnet)) {
+ $subnet = gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
+ } else if (is_subnetv6($subnet)) {
+ $subnet = gen_subnetv6($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
+ }
+ if ($returnsubnetsonly) {
+ $networks_arr[] = $subnet;
+ } else {
+ $networks_arr[] = array(
+ 'subnet' => $subnet,
+ 'if' => $vip['interface'],
+ 'ip' => $vip['subnet']);
+ }
+ }
+ }
+ foreach (get_staticroutes() as $netent) {
+ if (is_subnet($netent['network'])) {
+ if ($returnsubnetsonly) {
+ $networks_arr[] = $netent['network'];
+ } else if (isset($GatewaysList[$netent['gateway']])) {
+ $networks_arr[] = array(
+ 'subnet' => $netent['network'],
+ 'if' => $GatewaysList[$netent['gateway']]['friendlyiface'],
+ 'gateway' => $GatewaysList[$netent['gateway']]['gateway']);
+ }
+ }
+ }
+ if ($returnsubnetsonly) {
+ if (!empty($networks_arr)) {
+ $networks = implode(" ", $networks_arr);
+ }
+ return $networks;
+ } else {
+ return $networks_arr;
+ }
+}
+
+function filter_generate_optcfg_array() {
+ global $config, $FilterIflist;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_generate_optcfg_array() being called $mt\n";
+ }
+
+ read_layer7_config();
+ /* if list */
+ $iflist = get_configured_interface_with_descr();
+ foreach ($iflist as $if => $ifdetail) {
+ $oc = $config['interfaces'][$if];
+ $oic = array();
+ $oic['if'] = get_real_interface($if);
+ if (!does_interface_exist($oic['if'])) {
+ continue;
+ }
+ $oic['ifv6'] = get_real_interface($if, "inet6");
+ $oic['ip'] = get_interface_ip($if);
+ $oic['ipv6'] = get_interface_ipv6($if);
+ if (!is_ipaddrv4($oc['ipaddr']) && !empty($oc['ipaddr'])) {
+ $oic['type'] = $oc['ipaddr'];
+ }
+ if (!is_ipaddrv6($oc['ipaddrv6']) && !empty($oc['ipaddrv6'])) {
+ $oic['type6'] = $oc['ipaddrv6'];
+ }
+ if (!empty($oc['track6-interface'])) {
+ $oic['track6-interface'] = $oc['track6-interface'];
+ }
+ $oic['sn'] = get_interface_subnet($if);
+ $oic['snv6'] = get_interface_subnetv6($if);
+ $oic['mtu'] = empty($oc['mtu']) ? 1500 : $oc['mtu'];
+ $oic['mss'] = empty($oc['mss']) ? '' : $oc['mss'];
+ $oic['descr'] = $ifdetail;
+ $oic['sa'] = gen_subnet($oic['ip'], $oic['sn']);
+ $oic['sav6'] = gen_subnetv6($oic['ipv6'], $oic['snv6']);
+ $oic['nonat'] = $oc['nonat'];
+ $oic['alias-address'] = $oc['alias-address'];
+ $oic['alias-subnet'] = $oc['alias-subnet'];
+ $oic['gateway'] = $oc['gateway'];
+ $oic['gatewayv6'] = $oc['gatewayv6'];
+ $oic['spoofcheck'] = "yes";
+ $oic['bridge'] = link_interface_to_bridge($if);
+ $vips = link_interface_to_vips($if);
+ if (!empty($vips)) {
+ foreach ($vips as $vipidx => $vip) {
+ if (is_ipaddrv4($vip['subnet'])) {
+ if (!is_array($oic['vips'])) {
+ $oic['vips'] = array();
+ }
+ $oic['vips'][$vipidx]['ip'] = $vip['subnet'];
+ if (empty($vip['subnet_bits'])) {
+ $oic['vips'][$vipidx]['sn'] = 32;
+ } else {
+ $oic['vips'][$vipidx]['sn'] = $vip['subnet_bits'];
+ }
+ } else if (is_ipaddrv6($vip['subnet'])) {
+ if (!is_array($oic['vips6'])) {
+ $oic['vips6'] = array();
+ }
+ $oic['vips6'][$vipidx]['ip'] = $vip['subnet'];
+ if (empty($vip['subnet_bits'])) {
+ $oic['vips6'][$vipidx]['sn'] = 128;
+ } else {
+ $oic['vips6'][$vipidx]['sn'] = $vip['subnet_bits'];
+ }
+ }
+ }
+ }
+ unset($vips);
+ $FilterIflist[$if] = $oic;
+ }
+
+ if ($config['pptpd']['mode'] == "server" || $config['pptpd']['mode'] == "redir") {
+ $oic = array();
+ $oic['if'] = 'pptp';
+ $oic['descr'] = 'pptp';
+ $oic['ip'] = $config['pptpd']['localip'];
+ $oic['sa'] = $config['pptpd']['remoteip'];
+ $oic['mode'] = $config['pptpd']['mode'];
+ $oic['virtual'] = true;
+ if ($config['pptpd']['pptp_subnet'] <> "") {
+ $oic['sn'] = $config['pptpd']['pptp_subnet'];
+ } else {
+ $oic['sn'] = "32";
+ }
+ $FilterIflist['pptp'] = $oic;
+ }
+ if ($config['l2tp']['mode'] == "server") {
+ $oic = array();
+ $oic['if'] = 'l2tp';
+ $oic['descr'] = 'L2TP';
+ $oic['ip'] = $config['l2tp']['localip'];
+ $oic['sa'] = $config['l2tp']['remoteip'];
+ if ($config['l2tp']['l2tp_subnet'] <> "") {
+ $oic['sn'] = $config['l2tp']['l2tp_subnet'];
+ } else {
+ $oic['sn'] = "32";
+ }
+ $oic['mode'] = $config['l2tp']['mode'];
+ $oic['virtual'] = true;
+ $FilterIflist['l2tp'] = $oic;
+ }
+ if (is_array($config['pppoes']['pppoe']) && (count($config['pppoes']['pppoe']) > 0)) {
+ $pppoeifs = array();
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ if ($pppoe['mode'] == "server") {
+ $oic = array();
+ $oic['if'] = 'pppoe';
+ $oic['descr'] = 'pppoe';
+ $oic['ip'] = $pppoe['localip'];
+ $oic['sa'] = $pppoe['remoteip'];
+ $oic['mode'] = $pppoe['mode'];
+ $oic['virtual'] = true;
+ if ($pppoe['pppoe_subnet'] <> "") {
+ $oic['sn'] = $pppoe['pppoe_subnet'];
+ } else {
+ $oic['sn'] = "32";
+ }
+ $pppoeifs[] = $oic;
+ }
+ }
+ if (count($pppoeifs)) {
+ $FilterIflist['pppoe'] = $pppoeifs;
+ }
+ }
+ /* add ipsec interfaces */
+ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
+ $oic = array();
+ $oic['if'] = 'enc0';
+ $oic['descr'] = 'IPsec';
+ $oic['type'] = "none";
+ $oic['virtual'] = true;
+ $FilterIflist['enc0'] = $oic;
+ }
+ /* add openvpn interfaces */
+ if ($config['openvpn']['openvpn-server'] || $config['openvpn']['openvpn-client']) {
+ $oic = array();
+ $oic['if'] = "openvpn";
+ $oic['descr'] = 'OpenVPN';
+ $oic['type'] = "none";
+ $oic['virtual'] = true;
+ $FilterIflist['openvpn'] = $oic;
+ }
+ /* add interface groups */
+ if (is_array($config['ifgroups']['ifgroupentry'])) {
+ foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
+ $oc = array();
+ $oc['if'] = $ifgen['ifname'];
+ $oc['descr'] = $ifgen['ifname'];
+ $oc['virtual'] = true;
+ $FilterIflist[$ifgen['ifname']] = $oc;
+ }
+ }
+}
+
+function filter_flush_nat_table() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_flush_nat_table() being called $mt\n";
+ }
+ return mwexec("/sbin/pfctl -F nat");
+}
+
+function filter_flush_state_table() {
+ return mwexec("/sbin/pfctl -F state");
+}
+
+function filter_get_reflection_interfaces($natif = "") {
+ global $FilterIflist;
+
+ $nat_if_list = array();
+
+ foreach ($FilterIflist as $ifent => $ifname) {
+ if ($ifname['if'] == $natif) {
+ continue;
+ }
+
+ /* Do not add reflection redirects for interfaces with gateways */
+ if (interface_has_gateway($ifent)) {
+ continue;
+ }
+
+ $nat_if_list[] = $ifname['if'];
+ }
+
+ return $nat_if_list;
+}
+
+function filter_generate_reflection_nat($rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
+ global $config, $FilterIflist;
+
+ if (!isset($config['system']['enablenatreflectionhelper'])) {
+ return "";
+ }
+
+ // Initialize natrules holder string
+ $natrules = "";
+
+ update_filter_reload_status(sprintf(gettext("Creating reflection NAT rule for %s..."), $rule['descr']));
+
+ /* TODO: Add this option to port forwards page. */
+ if (isset($rule['staticnatport'])) {
+ $static_port = " static-port";
+ } else {
+ $static_port = " port 1024:65535";
+ }
+
+ if (!empty($protocol)) {
+ $protocol_text = " proto {$protocol}";
+ } else {
+ $protocol_text = "";
+ }
+
+ if (empty($target_subnet) || !is_numeric($target_subnet)) {
+ $target_subnet = 32;
+ }
+
+ if (!is_array($route_table)) {
+ /* get a simulated IPv4-only route table based on the config */
+ $route_table = filter_get_direct_networks_list(false);
+ foreach ($route_table as $rt_key => $rt_ent) {
+ if (!is_subnetv4($rt_ent['subnet'])) {
+ unset($route_table[$rt_key]);
+ }
+ if (isset($route_table[$rt_key]) && isset($FilterIflist[$rt_ent['if']]['if'])) {
+ $route_table[$rt_key]['if'] = $FilterIflist[$rt_ent['if']]['if'];
+ }
+ }
+ }
+
+ /* Check if the target is accessed through a static route */
+ foreach ($route_table as $route) {
+ if (isset($route['gateway']) && is_ipaddr($route['gateway'])) {
+ $subnet_split = explode("/", $route['subnet']);
+ if (in_array($route['if'], $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
+ $target_ip = $route['gateway'];
+ $target_subnet = 32;
+ break;
+ }
+ }
+ }
+
+ /* Search for matching subnets in the routing table */
+ foreach ($route_table as $route) {
+ $subnet = $route['subnet'];
+ $subnet_split = explode("/", $subnet);
+ $subnet_if = $route['if'];
+ /* Blacklist invalid "from" sources since they can be picked up accidentally and cause rule errors. */
+ $no_reflect_from = array("l2tp");
+ if (in_array($subnet_if, $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
+ $ifsubnet_ip = "";
+ /* Find interface IP to use for NAT */
+ foreach ($route_table as $ifnetwork) {
+ if (isset($ifnetwork['ip']) && is_ipaddr($ifnetwork['ip']) && $ifnetwork['if'] == $subnet_if && ip_in_subnet($ifnetwork['ip'], $subnet)) {
+ $ifsubnet_ip = $ifnetwork['ip'];
+ break;
+ }
+ }
+ if(!empty($ifsubnet_ip) && !in_array($subnet, $no_reflect_from)) {
+ $subnets = array($subnet);
+ /* Find static routes that also need to be referenced in the NAT rule */
+ foreach ($route_table as $rtentry) {
+ if (isset($rtentry['gateway']) && is_ipaddr($rtentry['gateway']) && $rtentry['if'] == $subnet_if && ip_in_subnet($rtentry['gateway'], $subnet)) {
+ $subnets[] = $rtentry['subnet'];
+ }
+ }
+ if (count($subnets) > 1) {
+ $subnet = "{ " . implode(" ", $subnets) . " }";
+ }
+ $natrules .= "no nat on {$subnet_if}{$protocol_text} from {$subnet_if} to {$target}\n";
+ $natrules .= "nat on {$subnet_if}{$protocol_text} from {$subnet} to {$target} -> {$ifsubnet_ip}{$static_port}\n";
+ }
+ }
+ }
+
+ if (!empty($natrules)) {
+ $natrules .= "\n";
+ }
+
+ return $natrules;
+}
+
+function filter_generate_reflection_proxy($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, &$starting_localhost_port, &$reflection_txt) {
+ global $FilterIflist, $config;
+
+ // Initialize natrules holder string
+ $natrules = "";
+ $reflection_txt = array();
+
+ if (!empty($rdr_ifs)) {
+ if ($config['system']['reflectiontimeout']) {
+ $reflectiontimeout = $config['system']['reflectiontimeout'];
+ } else {
+ $reflectiontimeout = "2000";
+ }
+
+ update_filter_reload_status(sprintf(gettext("Creating reflection rule for %s..."), $rule['descr']));
+
+ $rdr_if_list = implode(" ", $rdr_ifs);
+ if (count($rdr_ifs) > 1) {
+ $rdr_if_list = "{ {$rdr_if_list} }";
+ }
+
+ $natrules .= "\n# Reflection redirects\n";
+
+ $localport = $rule['local-port'];
+ if (!empty($localport) && is_alias($localport)) {
+ $localport = filter_expand_alias($localport);
+ $localport = explode(" ", trim($localport));
+ // The translation port for rdr, when specified, does not support more than one port or range.
+ // Emulating for behavior consistent with the original port forward.
+ $localport = $localport[0];
+ }
+
+ if (is_alias($rule['destination']['port'])) {
+ if (empty($localport) || $rule['destination']['port'] == $rule['local-port']) {
+ $dstport = filter_expand_alias($rule['destination']['port']);
+ $dstport = array_filter(explode(" ", trim($dstport)));
+ $localport = "";
+ } else if (!empty($localport)) {
+ $dstport = array($localport);
+ }
+ } else {
+ $dstport = array(str_replace("-", ":", $rule['destination']['port']));
+ $dstport_split = explode(":", $dstport[0]);
+
+ if (!empty($localport) && $dstport_split[0] != $rule['local-port']) {
+ if (!is_alias($rule['local-port']) && $dstport_split[1] && $dstport_split[0] != $dstport_split[1]) {
+ $localendport = $localport + ($dstport_split[1] - $dstport_split[0]);
+ $localport .= ":$localendport";
+ }
+
+ $dstport = array($localport);
+ } else {
+ $localport = "";
+ }
+ }
+
+ $dstaddr = explode(" ", $dstaddr_port);
+ if ($dstaddr[2]) {
+ $rflctintrange = array_pop($dstaddr);
+ array_pop($dstaddr);
+ } else {
+ return "";
+ }
+ $dstaddr = implode(" ", $dstaddr);
+ if (empty($dstaddr) || trim($dstaddr) == "0.0.0.0" || strtolower(trim($dstaddr)) == "port") {
+ return "";
+ }
+
+ if (isset($rule['destination']['any'])) {
+ if (!$rule['interface']) {
+ $natif = "wan";
+ } else {
+ $natif = $rule['interface'];
+ }
+
+ if (!isset($FilterIflist[$natif])) {
+ return "";
+ }
+ if (is_ipaddr($FilterIflist[$natif]['ip'])) {
+ $dstaddr = $FilterIflist[$natif]['ip'];
+ } else {
+ return "";
+ }
+
+ if (!empty($FilterIflist[$natif]['sn'])) {
+ $dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
+ }
+ }
+
+ switch ($rule['protocol']) {
+ case "tcp/udp":
+ $protocol = "{ tcp udp }";
+ $reflect_protos = array('tcp', 'udp');
+ break;
+ case "tcp":
+ case "udp":
+ $protocol = $rule['protocol'];
+ $reflect_protos = array($rule['protocol']);
+ break;
+ default:
+ return "";
+ break;
+ }
+
+ if (!empty($nordr)) {
+ $natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
+ return $natrules;
+ }
+
+ if (is_alias($rule['target'])) {
+ $target = filter_expand_alias($rule['target']);
+ } else if (is_ipaddr($rule['target'])) {
+ $target = $rule['target'];
+ } else if (is_ipaddr($FilterIflist[$rule['target']]['ip'])) {
+ $target = $FilterIflist[$rule['target']]['ip'];
+ } else {
+ return "";
+ }
+ $starting_localhost_port_tmp = $starting_localhost_port;
+ $toomanyports = false;
+ /* only install reflection rules for < 19991 items */
+ foreach ($dstport as $loc_pt) {
+ if ($starting_localhost_port < 19991) {
+ $toadd_array = array();
+ $inetdport = $starting_localhost_port;
+ $rflctrange = $starting_localhost_port;
+
+ $loc_pt = explode(":", $loc_pt);
+ if ($loc_pt[1] && $loc_pt[1] > $loc_pt[0]) {
+ $delta = $loc_pt[1] - $loc_pt[0];
+ } else {
+ $delta = 0;
+ }
+
+ if (($inetdport + $delta + 1) - $starting_localhost_port_tmp > 500) {
+ log_error("Not installing NAT reflection rules for a port range > 500");
+ $inetdport = $starting_localhost_port;
+ $toadd_array = array();
+ $toomanyports = true;
+ break;
+ } else if (($inetdport + $delta) > 19990) {
+ log_error("Installing partial NAT reflection rules. Maximum 1,000 reached.");
+ $delta = 19990 - $inetdport;
+ $loc_pt[1] = $loc_pt[0] + $delta;
+ if ($delta == 0) {
+ unset($loc_pt[1]);
+ }
+ $toomanyports = true;
+
+ if (!empty($localport)) {
+ if (is_alias($rule['destination']['port'])) {
+ $rflctintrange = alias_expand($rule['destination']['port']);
+ } else {
+ if ($dstport_split[1]) {
+ $dstport_split[1] = $dstport_split[0] + $inetdport + $delta - $starting_localhost_port;
+ }
+ $rflctintrange = implode(":", $dstport_split);
+ }
+ }
+ }
+
+ if (empty($localport)) {
+ $rflctintrange = implode(":", $loc_pt);
+ }
+ if ($inetdport + $delta > $starting_localhost_port) {
+ $rflctrange .= ":" . ($inetdport + $delta);
+ }
+ $starting_localhost_port = $inetdport + $delta + 1;
+ $toadd_array = array_merge($toadd_array, range($loc_pt[0], $loc_pt[0] + $delta));
+
+ if (!empty($toadd_array)) {
+ $rtarget = explode(" ", trim($target));
+ foreach ($toadd_array as $tda) {
+ if (empty($tda)) {
+ continue;
+ }
+ foreach ($reflect_protos as $reflect_proto) {
+ if ($reflect_proto == "udp") {
+ $socktype = "dgram";
+ $dash_u = "-u ";
+ $wait = "wait\t";
+ } else {
+ $socktype = "stream";
+ $dash_u = "";
+ $wait = "nowait/0";
+ }
+ foreach ($rtarget as $targip) {
+ if (empty($targip)) {
+ continue;
+ }
+ $reflection_txt[] = "{$inetdport}\t{$socktype}\t{$reflect_proto}\t{$wait}\tnobody\t/usr/bin/nc\tnc {$dash_u}-w {$reflectiontimeout} {$targip} {$tda}\n";
+ }
+ }
+ $inetdport++;
+ }
+ $natrules .= "rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange} tag PFREFLECT -> 127.0.0.1 port {$rflctrange}\n";
+ }
+ }
+
+ if ($toomanyports) {
+ break;
+ }
+ }
+
+ $reflection_txt = array_unique($reflection_txt);
+ }
+
+ return $natrules;
+}
+
+function filter_nat_rules_automatic_tonathosts($with_descr = false) {
+ global $config, $FilterIflist, $GatewaysList;
+
+ $tonathosts = array("127.0.0.0/8");
+ $descriptions = array(gettext("localhost"));
+
+ foreach (get_staticroutes() as $route) {
+ $netip = explode("/", $route['network']);
+ if (isset($GatewaysList[$route['gateway']])) {
+ $gateway =& $GatewaysList[$route['gateway']];
+ if (!interface_has_gateway($gateway['interface']) && is_private_ip($netip[0])) {
+ $tonathosts[] = $route['network'];
+ $descriptions[] = gettext("static route");
+ }
+ }
+ }
+
+ /* create outbound nat entries for all local networks */
+ foreach ($FilterIflist as $ocname => $oc) {
+ if (interface_has_gateway($ocname)) {
+ continue;
+ }
+ if (is_ipaddr($oc['alias-address'])) {
+ $tonathosts[] = "{$oc['alias-address']}/{$oc['alias-subnet']}";
+ $descriptions[] = $oc['descr'] . " " . gettext("DHCP alias address");
+ }
+ if ($oc['sa']) {
+ $tonathosts[] = "{$oc['sa']}/{$oc['sn']}";
+ $descriptions[] = $oc['descr'];
+ if (isset($oc['vips']) && is_array($oc['vips'])) {
+ $if_subnets = array("{$oc['sa']}/{$oc['sn']}");
+ foreach ($oc['vips'] as $vip) {
+ if (!is_ipaddrv4($vip['ip'])) {
+ continue;
+ }
+
+ foreach ($if_subnets as $subnet) {
+ if (ip_in_subnet($vip['ip'], $subnet)) {
+ continue 2;
+ }
+ }
+
+ $network = gen_subnet($vip['ip'], $vip['sn']);
+ array_unshift($tonathosts, $network . '/' . $vip['sn']);
+ array_unshift($descriptions, "Virtual IP ({$oc['descr']})");
+ $if_subnets[] = $network . '/' . $vip['sn'];
+ unset($network);
+ }
+ unset($if_subnets);
+ }
+ }
+ }
+
+ /* PPTP subnet */
+ if (($config['pptpd']['mode'] == "server") && is_private_ip($config['pptpd']['remoteip'])) {
+ if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units'])) {
+ $pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
+ long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
+ } else {
+ $pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
+ long2ip32(ip2long($config['pptpd']['remoteip'])));
+ }
+
+ foreach ($pptp_subnets as $subnet) {
+ $tonathosts[] = $subnet;
+ $descriptions[] = gettext("PPTP server");
+ }
+ }
+
+ /* PPPoE subnet */
+ if (is_array($FilterIflist['pppoe'])) {
+ foreach ($FilterIflist['pppoe'] as $pppoe) {
+ if (is_private_ip($pppoe['ip'])) {
+ $tonathosts[] = "{$pppoe['sa']}/{$pppoe['sn']}";
+ $descriptions[] = gettext("PPPoE server");
+ }
+ }
+ }
+
+ /* L2TP subnet */
+ if (isset($FilterIflist['l2tp']) && $FilterIflist['l2tp']['mode'] == "server") {
+ $l2tp_sa = $FilterIflist['l2tp']['sa'];
+ $l2tp_sn = $FilterIflist['l2tp']['sn'];
+ if (is_private_ip($l2tp_sa) && !empty($l2tp_sn)) {
+ $tonathosts[] = "{$l2tp_sa}/{$l2tp_sn}";
+ $descriptions[] = gettext("L2TP server");
+ }
+ }
+
+ /* add openvpn interfaces */
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $ovpnsrv) {
+ if (!isset($ovpnsrv['disable']) && !empty($ovpnsrv['tunnel_network'])) {
+ $tonathosts[] = $ovpnsrv['tunnel_network'];
+ $descriptions[] = gettext("OpenVPN server");
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as $ovpncli) {
+ if (!isset($ovpncli['disable']) && !empty($ovpncli['tunnel_network'])) {
+ $tonathosts[] = $ovpncli['tunnel_network'];
+ $descriptions[] = gettext("OpenVPN client");
+ }
+ }
+ }
+
+ /* IPsec mode_cfg subnet */
+ if ((isset($config['ipsec']['client']['enable'])) &&
+ (!empty($config['ipsec']['client']['pool_address'])) &&
+ (!empty($config['ipsec']['client']['pool_netbits']))) {
+ $tonathosts[] = "{$config['ipsec']['client']['pool_address']}/{$config['ipsec']['client']['pool_netbits']}";
+ $descriptions[] = gettext("IPsec client");
+ }
+
+ if ($with_descr) {
+ $combined = array();
+ foreach ($tonathosts as $idx => $subnet) {
+ $combined[] = array(
+ "subnet" => $subnet,
+ "descr" => $descriptions[$idx]);
+ }
+
+ return $combined;
+ } else {
+ return $tonathosts;
+ }
+}
+
+function filter_nat_rules_outbound_automatic($src) {
+ global $config, $FilterIflist;
+
+ $rules = array();
+ foreach ($FilterIflist as $if => $ifcfg) {
+ if (substr($ifcfg['if'], 0, 4) == "ovpn") {
+ continue;
+ }
+ if (!interface_has_gateway($if)) {
+ continue;
+ }
+
+ $natent = array();
+ $natent['interface'] = $if;
+ $natent['source']['network'] = $src;
+ $natent['dstport'] = "500";
+ $natent['target'] = "";
+ $natent['destination']['any'] = true;
+ $natent['staticnatport'] = true;
+ $natent['descr'] = gettext('Auto created rule for ISAKMP');
+ $rules[] = $natent;
+
+ $natent = array();
+ $natent['interface'] = $if;
+ $natent['source']['network'] = $src;
+ $natent['sourceport'] = "";
+ $natent['target'] = "";
+ $natent['destination']['any'] = true;
+ $natent['natport'] = "";
+ $natent['descr'] = gettext('Auto created rule');
+ if (isset($ifcfg['nonat'])) {
+ $natent['nonat'] = true;
+ }
+ $rules[] = $natent;
+ }
+
+ return $rules;
+}
+
+/* Generate a 'nat on' or 'no nat on' rule for given interface */
+function filter_nat_rules_generate_if ($if, $src = "any", $srcport = "", $dst = "any", $dstport = "", $natip = "", $natport = "", $nonat = false, $staticnatport = false, $proto = "", $poolopts = "") {
+ global $config, $FilterIflist;
+ /* XXX: billm - any idea if this code is needed? */
+ if ($src == "/32" || $src{0} == "/") {
+ return "# src incorrectly specified\n";
+ }
+ if ($natip != "") {
+ if (is_subnet($natip)) {
+ $tgt = $natip;
+ } elseif (is_alias($natip)) {
+ $tgt = "\${$natip}";
+ } else {
+ $tgt = "{$natip}/32";
+ }
+ } else {
+ $natip = get_interface_ip($if);
+ if (is_ipaddr($natip)) {
+ $tgt = "{$natip}/32";
+ } else {
+ $tgt = "(" . $FilterIflist[$if]['if'] . ")";
+ }
+ }
+ /* Add the protocol, if defined */
+ if (!empty($proto) && $proto != "any") {
+ if ($proto == "tcp/udp") {
+ $protocol = " proto { tcp udp }";
+ } else {
+ $protocol = " proto {$proto}";
+ }
+ } else {
+ $protocol = "";
+ }
+ /* Set tgt for IPv6 */
+ if ($proto == "ipv6") {
+ $natip = get_interface_ipv6($if);
+ if (is_ipaddrv6($natip)) {
+ $tgt = "{$natip}/128";
+ }
+ }
+ /* Add the hard set source port (useful for ISAKMP) */
+ if ($natport != "") {
+ $tgt .= " port {$natport}";
+ }
+ /* sometimes this gets called with "" instead of a value */
+ if ($src == "") {
+ $src = "any";
+ }
+ /* Match on this source port */
+ if ($srcport != "") {
+ $srcportexpand = alias_expand($srcport);
+ if (!$srcportexpand) {
+ $srcportexpand = $srcport;
+ }
+ $src .= " port {$srcportexpand}";
+ }
+ /* sometimes this gets called with "" instead of a value */
+ if ($dst == "") {
+ $dst = "any";
+ }
+ /* Match on this dest port */
+ if ($dstport != "") {
+ $dstportexpand = alias_expand($dstport);
+ if (!$dstportexpand) {
+ $dstportexpand = $dstport;
+ }
+ $dst .= " port {$dstportexpand}";
+ }
+ /* outgoing static-port option, hamachi, Grandstream, VOIP, etc */
+ $staticnatport_txt = "";
+ if ($staticnatport) {
+ $staticnatport_txt = "static-port";
+ } elseif (!$natport) {
+ $tgt .= " port 1024:65535"; // set source port range
+ }
+ /* Allow for negating NAT entries */
+ if ($nonat) {
+ $nat = "no nat";
+ $target = "";
+ $staticnatport_txt = "";
+ $poolopts = "";
+ } else {
+ $nat = "nat";
+ $target = "-> {$tgt}";
+ }
+ $if_friendly = $FilterIflist[$if]['descr'];
+ /* Put all the pieces together */
+ if ($if_friendly) {
+ $natrule = "{$nat} on \${$if_friendly} {$protocol} from {$src} to {$dst} {$target} {$poolopts} {$staticnatport_txt}\n";
+ } else {
+ $natrule .= "# Could not convert {$if} to friendly name(alias)\n";
+ }
+ return $natrule;
+}
+
+function filter_nat_rules_generate() {
+ global $config, $g, $after_filter_configure_run, $FilterIflist, $GatewaysList, $aliases;
+
+ $natrules = "no nat proto carp\n";
+ $natrules .= "no rdr proto carp\n";
+ $natrules .= "nat-anchor \"natearly/*\"\n";
+
+ $natrules .= "nat-anchor \"natrules/*\"\n\n";
+ update_filter_reload_status(gettext("Creating 1:1 rules..."));
+
+ $reflection_txt = "";
+ $route_table = "";
+
+ /* any 1:1 mappings? */
+ if (is_array($config['nat']['onetoone'])) {
+ foreach ($config['nat']['onetoone'] as $rule) {
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+
+ $sn = "";
+ $sn1 = "";
+ $target = alias_expand($rule['external']);
+ if (!$target) {
+ $natrules .= "# Unresolvable alias {$rule['target']}\n";
+ continue; /* unresolvable alias */
+ }
+
+ if (!$rule['interface']) {
+ $natif = "wan";
+ } else {
+ $natif = $rule['interface'];
+ }
+ if (!isset($FilterIflist[$natif])) {
+ continue;
+ }
+
+ $srcaddr = filter_generate_address($rule, 'source');
+ $dstaddr = filter_generate_address($rule, 'destination');
+ if (!$dstaddr) {
+ $dstaddr = $FilterIflist[$natif]['ip'];
+ }
+
+ $srcaddr = trim($srcaddr);
+ $dstaddr = trim($dstaddr);
+
+ $tmp = explode('/', $srcaddr);
+ $srcip = $tmp[0];
+ if (!empty($tmp[1]) && is_numeric($tmp[1])) {
+ $sn = $tmp[1];
+ $sn1 = "/{$sn}";
+ }
+
+ $natif = $FilterIflist[$natif]['if'];
+
+ /*
+ * If reflection is enabled, turn on extra redirections
+ * for this rule by adding other interfaces to an rdr rule.
+ */
+ if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable") &&
+ ($rule['natreflection'] != "disable")) {
+ $nat_if_list = filter_get_reflection_interfaces($natif);
+ } else {
+ $nat_if_list = array();
+ }
+
+ $natrules .= "binat on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n";
+ if (!empty($nat_if_list)) {
+ $binat_if_list = implode(" ", $nat_if_list);
+ $binat_if_list = "{ {$binat_if_list} }";
+ $reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n";
+ }
+
+ $nat_if_list = array_merge(array($natif), $nat_if_list);
+ $reflection_txt .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, "", $srcaddr, $srcip, $sn);
+ }
+ }
+
+ /* Add binat rules for Network Prefix translation */
+ if (is_array($config['nat']['npt'])) {
+ foreach ($config['nat']['npt'] as $rule) {
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+
+ if (!$rule['interface']) {
+ $natif = "wan";
+ } else {
+ $natif = $rule['interface'];
+ }
+ if (!isset($FilterIflist[$natif])) {
+ continue;
+ }
+
+ $srcaddr = filter_generate_address($rule, 'source');
+ $dstaddr = filter_generate_address($rule, 'destination');
+
+ $srcaddr = trim($srcaddr);
+ $dstaddr = trim($dstaddr);
+
+ $natif = $FilterIflist[$natif]['descr'];
+
+ $natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n";
+ $natrules .= "binat on \${$natif} from any to {$dstaddr} -> {$srcaddr}\n";
+
+ }
+ }
+
+ /* ipsec nat */
+ if (is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
+ if (is_array($config['ipsec']['phase2'])) {
+ foreach ($config['ipsec']['phase2'] as $ph2ent) {
+ if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid'])) {
+ if (!function_exists('ipsec_idinfo_to_cidr')) {
+ require_once("ipsec.inc");
+ }
+ if (!is_array($ph2ent['localid'])) {
+ $ph2ent['localid'] = array();
+ }
+ $ph2ent['localid']['mode'] = $ph2ent['mode'];
+ $local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid']);
+ if (empty($local_subnet) || $local_subnet == "0.0.0.0/0") {
+ continue;
+ }
+ if (!is_subnet($local_subnet) && !is_ipaddr($local_subnet)) {
+ continue;
+ }
+ if (!is_array($ph2ent['natlocalid'])) {
+ $ph2ent['natlocalid'] = array();
+ }
+ $ph2ent['natlocalid']['mode'] = $ph2ent['mode'];
+ $natlocal_subnet = ipsec_idinfo_to_cidr($ph2ent['natlocalid']);
+ if (empty($natlocal_subnet) || $natlocal_subnet == "0.0.0.0/0") {
+ continue;
+ }
+ if (!is_subnet($natlocal_subnet) && !is_ipaddr($natlocal_subnet)) {
+ continue;
+ }
+ if (!is_array($ph2ent['remoteid'])) {
+ $ph2ent['remoteid'] = array();
+ }
+ $ph2ent['remoteid']['mode'] = $ph2ent['mode'];
+ $remote_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
+ if (empty($remote_subnet)) {
+ continue;
+ }
+ if (!is_subnet($remote_subnet) && !is_ipaddr($remote_subnet)) {
+ continue;
+ }
+ if ($remote_subnet == "0.0.0.0/0") {
+ $remote_subnet = "any";
+ }
+ if (is_ipaddr($natlocal_subnet) && !is_ipaddr($local_subnet)) {
+ $nattype = "nat";
+ } else {
+ list($natnet, $natmask) = explode('/', $natlocal_subnet);
+ list($locnet, $locmask) = explode('/', $local_subnet);
+ if (intval($natmask) != intval($locmask)) {
+ $nattype = "nat";
+ } else {
+ $nattype = "binat";
+ }
+ unset($natnet, $natmask, $locnet, $locmask);
+ }
+ $natrules .= "{$nattype} on enc0 from {$local_subnet} to {$remote_subnet} -> {$natlocal_subnet}\n";
+ }
+ }
+ }
+ }
+
+ if ($config['nat']['outbound']['mode'] == "disabled") {
+ $natrules .= "\n# Outbound NAT rules are disabled\n";
+ }
+
+ if ($config['nat']['outbound']['mode'] == "advanced" || $config['nat']['outbound']['mode'] == "hybrid") {
+ $natrules .= "\n# Outbound NAT rules (manual)\n";
+ /* advanced outbound rules */
+ if (is_array($config['nat']['outbound']['rule'])) {
+ foreach ($config['nat']['outbound']['rule'] as $obent) {
+ if (isset($obent['disabled'])) {
+ continue;
+ }
+ update_filter_reload_status(sprintf(gettext("Creating advanced outbound rule %s"), $obent['descr']));
+ $src = alias_expand($obent['source']['network']);
+ if (!$src) {
+ $src = $obent['source']['network'];
+ }
+ $dst = alias_expand($obent['destination']['address']);
+ if (!$dst) {
+ $dst = $obent['destination']['address'];
+ }
+ if (isset($obent['destination']['not']) && !isset($obent['destination']['any'])) {
+ $dst = "!" . $dst;
+ }
+
+ if (!$obent['interface'] || !isset($FilterIflist[$obent['interface']])) {
+ continue;
+ }
+
+ $obtarget = ($obent['target'] == "other-subnet") ? $obent['targetip'] . '/' . $obent['targetip_subnet']: $obent['target'];
+ $poolopts = (is_subnet($obtarget) || is_alias($obtarget)) ? $obent['poolopts'] : "";
+
+ $natrules .= filter_nat_rules_generate_if($obent['interface'],
+ $src,
+ $obent['sourceport'],
+ $dst,
+ $obent['dstport'],
+ $obtarget,
+ $obent['natport'],
+ isset($obent['nonat']),
+ isset($obent['staticnatport']),
+ $obent['protocol'],
+ $poolopts
+ );
+ }
+ }
+ }
+
+ /* outbound rules */
+ if ((!isset($config['nat']['outbound']['mode'])) ||
+ ($config['nat']['outbound']['mode'] == "automatic") ||
+ ($config['nat']['outbound']['mode'] == "hybrid")) {
+ $natrules .= "\n# Outbound NAT rules (automatic)\n";
+ /* standard outbound rules (one for each interface) */
+ update_filter_reload_status(gettext("Creating outbound NAT rules"));
+ $tonathosts_array = filter_nat_rules_automatic_tonathosts();
+ $tonathosts = implode(" ", $tonathosts_array);
+ $numberofnathosts = count($tonathosts_array);
+
+ $natrules .= "\n# Subnets to NAT \n";
+ if ($numberofnathosts > 0) {
+ update_filter_reload_status(gettext('Creating automatic outbound rules'));
+
+ if ($numberofnathosts > 4) {
+ $natrules .= "table <tonatsubnets> { {$tonathosts} }\n";
+ $macroortable = "<tonatsubnets>";
+ } else {
+ $natrules .= "tonatsubnets = \"{ {$tonathosts} }\"\n";
+ $macroortable = "\$tonatsubnets";
+ }
+
+ $a_outs = filter_nat_rules_outbound_automatic($macroortable);
+ foreach ($a_outs as $a_out) {
+ $natrules .= filter_nat_rules_generate_if($a_out['interface'],
+ $a_out['source']['network'],
+ $a_out['sourceport'],
+ $a_out['destination']['address'],
+ $a_out['dstport'],
+ $a_out['target'],
+ $a_out['natport'],
+ isset($a_out['nonat']),
+ isset($a_out['staticnatport']));
+ }
+ }
+ unset($tonathosts, $tonathosts_array, $numberofnathosts);
+ }
+
+ /* load balancer anchor */
+ $natrules .= "\n# Load balancing anchor\n";
+ $natrules .= "rdr-anchor \"relayd/*\"\n";
+
+ update_filter_reload_status(gettext("Setting up TFTP helper"));
+ $natrules .= "# TFTP proxy\n";
+ $natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
+
+ if (!empty($config['system']['tftpinterface'])) {
+ $tftpifs = explode(",", $config['system']['tftpinterface']);
+ foreach ($tftpifs as $tftpif) {
+ if ($FilterIflist[$tftpif]) {
+ $natrules .= "rdr pass on {$FilterIflist[$tftpif]['if']} proto udp from any to any port tftp -> 127.0.0.1 port 6969\n";
+ }
+ }
+ }
+
+ /* DIAG: add ipv6 NAT, if requested */
+ if ((isset($config['diag']['ipv6nat']['enable'])) &&
+ (is_ipaddr($config['diag']['ipv6nat']['ipaddr'])) &&
+ (is_array($FilterIflist['wan']))) {
+ /* XXX: FIX ME! IPV6 */
+ $natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto ipv6 from any to any -> {$config['diag']['ipv6nat']['ipaddr']}\n";
+ }
+
+ if (file_exists("/var/etc/inetd.conf")) {
+ @unlink("/var/etc/inetd.conf");
+ }
+ // Open inetd.conf write handle
+ $inetd_fd = fopen("/var/etc/inetd.conf", "w");
+ /* add tftp protocol helper */
+ fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
+
+ if (isset($config['nat']['rule'])) {
+ /* start reflection redirects on port 19000 of localhost */
+ $starting_localhost_port = 19000;
+ $natrules .= "# NAT Inbound Redirects\n";
+ foreach ($config['nat']['rule'] as $rule) {
+ update_filter_reload_status(sprintf(gettext("Creating NAT rule %s"), $rule['descr']));
+
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+
+ /* if item is an alias, expand */
+ $dstport = "";
+ $dstport[0] = alias_expand($rule['destination']['port']);
+ if (!$dstport[0]) {
+ $dstport = explode("-", $rule['destination']['port']);
+ }
+
+ /* if item is an alias, expand */
+ $localport = alias_expand($rule['local-port']);
+ if (!$localport || $dstport[0] == $localport) {
+ $localport = "";
+ } else if (is_alias($rule['local-port'])) {
+ $localport = filter_expand_alias($rule['local-port']);
+ if ($localport) {
+ $localport = explode(" ", trim($localport));
+ $localport = $localport[0];
+ $localport = " port {$localport}";
+ }
+ } else if (is_alias($rule['destination']['port'])) {
+ $localport = " port {$localport}";
+ } else {
+ if (($dstport[1]) && ($dstport[0] != $dstport[1])) {
+ $localendport = $localport + ($dstport[1] - $dstport[0]);
+
+ $localport .= ":$localendport";
+ }
+
+ $localport = " port {$localport}";
+ }
+
+ switch (strtolower($rule['protocol'])) {
+ case "tcp/udp":
+ $protocol = "{ tcp udp }";
+ break;
+ case "tcp":
+ case "udp":
+ $protocol = strtolower($rule['protocol']);
+ break;
+ default:
+ $protocol = strtolower($rule['protocol']);
+ $localport = "";
+ break;
+ }
+
+ $target = alias_expand($rule['target']);
+ if (!$target && !isset($rule['nordr'])) {
+ $natrules .= "# Unresolvable alias {$rule['target']}\n";
+ continue; /* unresolvable alias */
+ }
+
+ if (is_alias($rule['target'])) {
+ $target_ip = filter_expand_alias($rule['target']);
+ } else if (is_ipaddr($rule['target'])) {
+ $target_ip = $rule['target'];
+ } else if (is_ipaddr($FilterIflist[$rule['target']]['ip'])) {
+ $target_ip = $FilterIflist[$rule['target']]['ip'];
+ } else {
+ $target_ip = $rule['target'];
+ }
+ $target_ip = trim($target_ip);
+
+ if ($rule['associated-rule-id'] == "pass") {
+ $rdrpass = "pass ";
+ } else {
+ $rdrpass = "";
+ }
+
+ if (isset($rule['nordr'])) {
+ $nordr = "no ";
+ $rdrpass = "";
+ } else {
+ $nordr = "";
+ }
+
+ if (!$rule['interface']) {
+ $natif = "wan";
+ } else {
+ $natif = $rule['interface'];
+ }
+
+ if (!isset($FilterIflist[$natif])) {
+ continue;
+ }
+
+ $srcaddr = filter_generate_address($rule, 'source', true);
+ $dstaddr = filter_generate_address($rule, 'destination', true);
+ $srcaddr = trim($srcaddr);
+ $dstaddr = trim($dstaddr);
+
+ if (!$dstaddr) {
+ $dstaddr = $FilterIflist[$natif]['ip'];
+ }
+
+ $dstaddr_port = explode(" ", $dstaddr);
+ if (empty($dstaddr_port[0]) || strtolower(trim($dstaddr_port[0])) == "port") {
+ continue; // Skip port forward if no destination address found
+ }
+ $dstaddr_reflect = $dstaddr;
+ if (isset($rule['destination']['any'])) {
+ /* With reflection enabled, destination of 'any' has side effects
+ * that most people would not expect, so change it on reflection rules. */
+
+ if (!empty($FilterIflist[$natif]['ip'])) {
+ $dstaddr_reflect = $FilterIflist[$natif]['ip'];
+ } else {
+ // no IP, bail
+ continue;
+ }
+
+ if (!empty($FilterIflist[$natif]['sn'])) {
+ $dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
+ }
+
+ if ($dstaddr_port[2]) {
+ $dstaddr_reflect .= " port " . $dstaddr_port[2];
+ }
+ }
+
+ $natif = $FilterIflist[$natif]['if'];
+
+ $reflection_type = "none";
+ if ($rule['natreflection'] != "disable" && $dstaddr_port[0] != "0.0.0.0") {
+ if ($rule['natreflection'] == "enable") {
+ $reflection_type = "proxy";
+ } else if ($rule['natreflection'] == "purenat") {
+ $reflection_type = "purenat";
+ } else if (!isset($config['system']['disablenatreflection'])) {
+ if (isset($config['system']['enablenatreflectionpurenat'])) {
+ $reflection_type = "purenat";
+ } else {
+ $reflection_type = "proxy";
+ }
+ }
+ }
+
+ if ($reflection_type != "none") {
+ $nat_if_list = filter_get_reflection_interfaces($natif);
+ } else {
+ $nat_if_list = array();
+ }
+
+ if (empty($nat_if_list)) {
+ $reflection_type = "none";
+ }
+
+ $localport_nat = $localport;
+ if (empty($localport_nat) && $dstaddr_port[2]) {
+ $localport_nat = " port " . $dstaddr_port[2];
+ }
+
+ if ($srcaddr <> "" && $dstaddr <> "" && $natif) {
+ $natrules .= "{$nordr}rdr {$rdrpass}on {$natif} proto {$protocol} from {$srcaddr} to {$dstaddr}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
+
+ /* Does this rule redirect back to a internal host? */
+ if (isset($rule['destination']['any']) && !isset($rule['nordr']) && !isset($config['system']['enablenatreflectionhelper']) && !interface_has_gateway($rule['interface'])) {
+ $rule_interface_ip = find_interface_ip($natif);
+ $rule_interface_subnet = find_interface_subnet($natif);
+ if (!empty($rule_interface_ip) && !empty($rule_interface_subnet)) {
+ $rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
+ $natrules .= "\n";
+ $natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
+ $natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
+ }
+ }
+
+ if ($reflection_type != "none") {
+ if ($reflection_type == "proxy" && !isset($rule['nordr'])) {
+ $natrules .= filter_generate_reflection_proxy($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $starting_localhost_port, $reflection_rules);
+ $nat_if_list = array($natif);
+ foreach ($reflection_rules as $txtline) {
+ fwrite($inetd_fd, $txtline);
+ }
+ } else if ($reflection_type == "purenat" || isset($rule['nordr'])) {
+ $rdr_if_list = implode(" ", $nat_if_list);
+ if (count($nat_if_list) > 1) {
+ $rdr_if_list = "{ {$rdr_if_list} }";
+ }
+ $natrules .= "\n# Reflection redirect\n";
+ $natrules .= "{$nordr}rdr {$rdrpass}on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
+ $nat_if_list = array_merge(array($natif), $nat_if_list);
+ }
+ }
+
+ if (empty($nat_if_list)) {
+ $nat_if_list = array($natif);
+ }
+
+ $natrules .= "\n";
+ if (!isset($rule['nordr'])) {
+ $natrules .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
+ }
+ }
+ }
+ }
+ fclose($inetd_fd); // Close file handle
+
+ if (isset($config['pptpd']['mode']) && ($config['pptpd']['mode'] != "off")) {
+ if ($config['pptpd']['mode'] == "redir") {
+ $pptpdtarget = $config['pptpd']['redir'];
+ $natrules .= "# PPTP\n";
+ $natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto gre from any to any -> {$pptpdtarget}\n";
+ $natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto tcp from any to any port 1723 -> {$pptpdtarget}\n";
+ }
+ }
+
+ $natrules .= discover_pkg_rules("nat");
+
+ $natrules .= "# UPnPd rdr anchor\n";
+ $natrules .= "rdr-anchor \"miniupnpd\"\n";
+
+ if (!empty($reflection_txt)) {
+ $natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt;
+ }
+
+ // Check if inetd is running, if not start it. If so, restart it gracefully.
+ $helpers = isvalidproc("inetd");
+ if (file_exists("/var/etc/inetd.conf")) {
+ if (!$helpers) {
+ mwexec("/usr/sbin/inetd -wW -R 0 -a 127.0.0.1 /var/etc/inetd.conf");
+ } else {
+ sigkillbypid("/var/run/inetd.pid", "HUP");
+ }
+ }
+
+ return $natrules;
+}
+
+function filter_generate_user_rule_arr($rule) {
+ global $config;
+ update_filter_reload_status(sprintf(gettext("Creating filter rule %s ..."), $rule['descr']));
+ $ret = array();
+ $line = filter_generate_user_rule($rule);
+ $ret['rule'] = $line;
+ $ret['interface'] = $rule['interface'];
+ if ($rule['descr'] != "" and $line != "") {
+ $ret['descr'] = "label \"" . fix_rule_label("USER_RULE: {$rule['descr']}") . "\"";
+ } else {
+ $ret['descr'] = "label \"USER_RULE\"";
+ }
+
+ return $ret;
+}
+
+function filter_generate_port(& $rule, $target = "source", $isnat = false) {
+
+ $src = "";
+
+ $rule['protocol'] = strtolower($rule['protocol']);
+ if (in_array($rule['protocol'], array("tcp", "udp", "tcp/udp"))) {
+ if ($rule[$target]['port']) {
+ $srcport = explode("-", $rule[$target]['port']);
+ $srcporta = alias_expand($srcport[0]);
+ if (!$srcporta) {
+ log_error(sprintf(gettext("filter_generate_port: %s is not a valid {$target} port."), $srcport[0]));
+ } else if ((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
+ $src .= " port {$srcporta} ";
+ } else if (($srcport[0] == 1) && ($srcport[1] == 65535)) {
+ /* no need for a port statement here */
+ } else if ($isnat) {
+ $src .= " port {$srcport[0]}:{$srcport[1]}";
+ } else {
+ if (is_port($srcporta) && $srcport[1] == 65535) {
+ $src .= " port >= {$srcporta} ";
+ } else if ($srcport[0] == 1) {
+ $src .= " port <= {$srcport[1]} ";
+ } else {
+ $srcport[0]--;
+ $srcport[1]++;
+ $src .= " port {$srcport[0]} >< {$srcport[1]} ";
+ }
+ }
+ }
+ }
+
+ return $src;
+}
+
+function filter_address_add_vips_subnets(&$subnets, $if, $not) {
+ global $FilterIflist;
+
+ $if_subnets = array($subnets);
+
+ if ($not == true) {
+ $subnets = "!{$subnets}";
+ }
+
+ if (!isset($FilterIflist[$if]['vips']) || !is_array($FilterIflist[$if]['vips'])) {
+ return;
+ }
+
+ foreach ($FilterIflist[$if]['vips'] as $vip) {
+ foreach ($if_subnets as $subnet) {
+ if (ip_in_subnet($vip['ip'], $subnet)) {
+ continue 2;
+ }
+ }
+
+ if (is_ipaddrv4($vip['ip'])) {
+ if (!is_subnetv4($if_subnets[0])) {
+ continue;
+ }
+
+ $network = gen_subnet($vip['ip'], $vip['sn']);
+ } else if (is_ipaddrv6($vip['ip'])) {
+ if (!is_subnetv6($if_subnets[0])) {
+ continue;
+ }
+
+ $network = gen_subnetv6($vip['ip'], $vip['sn']);
+ } else {
+ continue;
+ }
+
+ $subnets .= ' ' . ($not == true ? '!' : '') . $network . '/' . $vip['sn'];
+ $if_subnets[] = $network . '/' . $vip['sn'];
+ }
+ unset($if_subnets);
+
+ if (strpos($subnets, ' ') !== false) {
+ $subnets = "{ {$subnets} }";
+ }
+}
+
+function filter_generate_address(& $rule, $target = "source", $isnat = false) {
+ global $FilterIflist, $config;
+ $src = "";
+
+ if (isset($rule[$target]['any'])) {
+ $src = "any";
+ } else if ($rule[$target]['network']) {
+ if (strstr($rule[$target]['network'], "opt")) {
+ $optmatch = "";
+ $matches = "";
+ if ($rule['ipprotocol'] == "inet6") {
+ if (preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
+ $opt_sa = $FilterIflist["opt{$optmatch[1]}"]['sav6'];
+ if (!is_ipaddrv6($opt_sa)) {
+ return "";
+ }
+ $src = $opt_sa . "/" . $FilterIflist["opt{$optmatch[1]}"]['snv6'];
+ /* check for opt$NUMip here */
+ } else if (preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
+ $src = $FilterIflist["opt{$matches[1]}"]['ipv6'];
+ if (!is_ipaddrv6($src)) {
+ return "";
+ }
+ if (isset($rule[$target]['not'])) {
+ $src = " !{$src}";
+ }
+ }
+ } else {
+ if (preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
+ $opt_sa = $FilterIflist["opt{$optmatch[1]}"]['sa'];
+ if (!is_ipaddrv4($opt_sa)) {
+ return "";
+ }
+ $src = $opt_sa . "/" . $FilterIflist["opt{$optmatch[1]}"]['sn'];
+ /* check for opt$NUMip here */
+ } else if (preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
+ $src = $FilterIflist["opt{$matches[1]}"]['ip'];
+ if (!is_ipaddrv4($src)) {
+ return "";
+ }
+ if (isset($rule[$target]['not'])) {
+ $src = " !{$src}";
+ }
+ }
+ }
+ } else {
+ if ($rule['ipprotocol'] == "inet6") {
+ switch ($rule[$target]['network']) {
+ case 'wan':
+ $wansa = $FilterIflist['wan']['sav6'];
+ if (!is_ipaddrv6($wansa)) {
+ return "";
+ }
+ $wansn = $FilterIflist['wan']['snv6'];
+ $src = "{$wansa}/{$wansn}";
+ break;
+ case 'wanip':
+ $src = $FilterIflist["wan"]['ipv6'];
+ if (!is_ipaddrv6($src)) {
+ return "";
+ }
+ break;
+ case 'lanip':
+ $src = $FilterIflist["lan"]['ipv6'];
+ if (!is_ipaddrv6($src)) {
+ return "";
+ }
+ break;
+ case 'lan':
+ $lansa = $FilterIflist['lan']['sav6'];
+ if (!is_ipaddrv6($lansa)) {
+ return "";
+ }
+ $lansn = $FilterIflist['lan']['snv6'];
+ $src = "{$lansa}/{$lansn}";
+ break;
+ case '(self)':
+ $src = "(self)";
+ break;
+ case 'pptp':
+ $pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
+ $pptpsnv6 = $FilterIflist['pptp']['snv6'];
+ $src = "{$pptpsav6}/{$pptpsnv6}";
+ break;
+ case 'pppoe':
+ if (is_array($FilterIflist['pppoe'])) {
+ $pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
+ $pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
+ $src = "{$pppoesav6}/{$pppoesnv6}";
+ }
+ }
+ if (isset($rule[$target]['not']) && !is_subnet($src)) {
+ $src = " !{$src}";
+ }
+ } else {
+ switch ($rule[$target]['network']) {
+ case 'wan':
+ $wansa = $FilterIflist['wan']['sa'];
+ if (!is_ipaddrv4($wansa)) {
+ return "";
+ }
+ $wansn = $FilterIflist['wan']['sn'];
+ $src = "{$wansa}/{$wansn}";
+ break;
+ case 'wanip':
+ $src = $FilterIflist["wan"]['ip'];
+ break;
+ case 'lanip':
+ $src = $FilterIflist["lan"]['ip'];
+ break;
+ case 'lan':
+ $lansa = $FilterIflist['lan']['sa'];
+ if (!is_ipaddrv4($lansa)) {
+ return "";
+ }
+ $lansn = $FilterIflist['lan']['sn'];
+ $src = "{$lansa}/{$lansn}";
+ break;
+ case '(self)':
+ $src = "(self)";
+ break;
+ case 'pptp':
+ if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units'])) {
+ $pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
+ } else {
+ $pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
+ }
+ if (empty($pptp_subnets)) {
+ return "";
+ }
+ if (isset($rule[$target]['not'])) {
+ array_walk($pptp_subnets, function (&$value, $key) {
+ $value="!{$value}";
+ });
+ }
+ $src = "{ " . implode(" ", $pptp_subnets) . " }";
+ break;
+ case 'pppoe':
+ /* XXX: This needs to be fixed somehow! */
+ if (is_array($FilterIflist['pppoe'])) {
+ $pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
+ $pppoesn = $FilterIflist['pppoe'][0]['sn'];
+ $src = "{$pppoesa}/{$pppoesn}";
+ }
+ break;
+ }
+ if ((isset($rule[$target]['not'])) &&
+ (!is_subnet($src)) &&
+ (strpos($src, '{') === false)) {
+ $src = " !{$src}";
+ }
+ }
+ }
+ if (is_subnet($src)) {
+ filter_address_add_vips_subnets($src, $rule[$target]['network'], isset($rule[$target]['not']));
+ }
+ } else if ($rule[$target]['address']) {
+ $expsrc = alias_expand($rule[$target]['address']);
+ if (isset($rule[$target]['not'])) {
+ $not = "!";
+ } else {
+ $not = "";
+ }
+ $src = " {$not} {$expsrc}";
+ }
+
+ if (empty($src)) {
+ return '';
+ }
+
+ $src .= filter_generate_port($rule, $target, $isnat);
+
+ return $src;
+}
+
+function filter_generate_user_rule($rule) {
+ global $config, $g, $FilterIflist, $GatewaysList;
+ global $layer7_rules_list, $dummynet_name_list;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_generate_user_rule() being called $mt\n";
+ }
+ /* don't include disabled rules */
+ if (isset($rule['disabled'])) {
+ return "# rule " . $rule['descr'] . " disabled \n";
+ }
+ update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
+ $pptpdcfg = $config['pptpd'];
+ $int = "";
+ $aline = array();
+
+ /* Check to see if the interface is in our list */
+ if (isset($rule['floating'])) {
+ if (isset($rule['interface']) && $rule['interface'] <> "") {
+ $interfaces = explode(",", $rule['interface']);
+ $ifliste = "";
+ foreach ($interfaces as $iface) {
+ if (array_key_exists($iface, $FilterIflist)) {
+ $ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
+ }
+ }
+ if ($ifliste <> "") {
+ $aline['interface'] = " on { {$ifliste} } ";
+ } else {
+ $aline['interface'] = "";
+ }
+ } else {
+ $aline['interface'] = "";
+ }
+ } else if (!array_key_exists($rule['interface'], $FilterIflist)) {
+ foreach ($FilterIflist as $oc) {
+ $items .= $oc['descr'] . " ";
+ }
+ return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
+ } else if ((array_key_exists($rule['interface'], $FilterIflist)) &&
+ (is_array($FilterIflist[$rule['interface']])) &&
+ (is_array($FilterIflist[$rule['interface']][0]))) {
+ /* Currently the only case for this is the pppoe server. There should be an existing macro with this name. */
+ $aline['interface'] = " on \$" . $rule['interface'] . " ";
+ } else {
+ $aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
+ }
+ $ifcfg = $FilterIflist[$rule['interface']];
+ if ($pptpdcfg['mode'] != "server") {
+ if (($rule['source']['network'] == "pptp") ||
+ ($rule['destination']['network'] == "pptp")) {
+ return "# source network or destination network == pptp on " . $rule['descr'];
+ }
+ }
+
+ switch ($rule['ipprotocol']) {
+ case "inet":
+ $aline['ipprotocol'] = "inet";
+ break;
+ case "inet6":
+ $aline['ipprotocol'] = "inet6";
+ break;
+ default:
+ $aline['ipprotocol'] = "";
+ break;
+ }
+
+ /* check for unresolvable aliases */
+ if ($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
+ $error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
+ file_notice("Filter_Reload", $error_text);
+ return "# {$error_text}";
+ }
+ if ($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
+ $error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
+ file_notice("Filter_Reload", $error_text);
+ return "# {$error_text}";
+ }
+ update_filter_reload_status("Setting up pass/block rules");
+ $type = $rule['type'];
+ if ($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
+ /* default (for older rules) is pass */
+ $type = "pass";
+ }
+ if ($type == "reject") {
+ $aline['type'] = "block return ";
+ } else {
+ $aline['type'] = $type . " ";
+ }
+ if (isset($rule['floating']) && $rule['floating'] == "yes") {
+ if ($rule['direction'] != "any") {
+ $aline['direction'] = " " . $rule['direction'] . " ";
+ }
+ } else {
+ /* ensure the direction is in */
+ $aline['direction'] = " in ";
+ }
+ if (isset($rule['log'])) {
+ $aline['log'] = "log ";
+ }
+ if (!isset($rule['floating']) || isset($rule['quick'])) {
+ $aline['quick'] = " quick ";
+ }
+
+ /* set the gateway interface */
+ update_filter_reload_status(sprintf(gettext("Setting up pass/block rules %s"), $rule['descr']));
+
+ /* do not process reply-to for gateway'd rules */
+ if ($rule['gateway'] == "" && $aline['direction'] <> "" && (interface_has_gateway($rule['interface']) || interface_has_gatewayv6($rule['interface'])) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
+ if ($rule['ipprotocol'] == "inet6") {
+ $rg = get_interface_gateway_v6($rule['interface']);
+ if (is_ipaddrv6($rg)) {
+ $aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
+ } else if ($rule['interface'] <> "pptp") {
+ log_error(sprintf(gettext("Could not find IPv6 gateway for interface (%s)."), $rule['interface']));
+ }
+ } else {
+ $rg = get_interface_gateway($rule['interface']);
+ if (is_ipaddrv4($rg)) {
+ $aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
+ } else if ($rule['interface'] <> "pptp") {
+ log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
+ }
+ }
+ }
+ /* if user has selected a custom gateway, lets work with it */
+ else if ($rule['gateway'] <> "" && $type == "pass") {
+ if (isset($GatewaysList[$rule['gateway']])) {
+ /* Add the load balanced gateways */
+ $aline['route'] = " \$GW{$rule['gateway']} ";
+ } else if (isset($config['system']['skip_rules_gw_down'])) {
+ return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
+ } else {
+ log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
+ }
+ }
+
+ if (isset($rule['protocol']) && !empty($rule['protocol'])) {
+ if ($rule['protocol'] == "tcp/udp") {
+ $aline['prot'] = " proto { tcp udp } ";
+ } elseif (($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6")) {
+ $aline['prot'] = " proto ipv6-icmp ";
+ } elseif ($rule['protocol'] == "icmp") {
+ $aline['prot'] = " proto icmp ";
+ } else {
+ $aline['prot'] = " proto {$rule['protocol']} ";
+ }
+ } else {
+ if ($rule['source']['port'] <> "" || $rule['destination']['port'] <> "") {
+ $aline['prot'] = " proto tcp ";
+ }
+ }
+ update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
+
+ /* source address */
+ $src = trim(filter_generate_address($rule, "source"));
+ if (empty($src) || ($src == "/")) {
+ return "# at the break!";
+ }
+ $aline['src'] = " from $src ";
+
+ /* OS signatures */
+ if (($rule['protocol'] == "tcp") && ($rule['os'] <> "")) {
+ $aline['os'] = " os \"{$rule['os']}\" ";
+ }
+
+ /* destination address */
+ $dst = trim(filter_generate_address($rule, "destination"));
+ if (empty($dst) || ($dst == "/")) {
+ return "# returning at dst $dst == \"/\"";
+ }
+ $aline['dst'] = "to $dst ";
+
+ //Layer7 support
+ $l7_present = false;
+ $l7_structures = array();
+ if (isset($rule['l7container']) && $rule['l7container'] != "none") {
+ $l7_present = true;
+ $l7rule =& $layer7_rules_list[$rule['l7container']];
+ $l7_structures = $l7rule->get_unique_structures();
+ $aline['divert'] = "divert-to " . $l7rule->GetRPort() . " ";
+ }
+ if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet")) {
+ $aline['icmp-type'] = "icmp-type {$rule['icmptype']} ";
+ }
+ if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet6")) {
+ $aline['icmp6-type'] = "icmp6-type {$rule['icmptype']} ";
+ }
+ if (!empty($rule['tag'])) {
+ if (ctype_digit($rule['tag'])) {
+ $aline['tag'] = " tag \"" .$rule['tag']. "\" ";
+ } else {
+ $aline['tag'] = " tag " .$rule['tag']. " ";
+ }
+ }
+ if (!empty($rule['tagged'])) {
+ $aline['tagged'] = " tagged " .$rule['tagged'] . " ";
+ }
+ if (!empty($rule['dscp'])) {
+ switch (strtolower($rule['dscp'])) {
+ case 'va':
+ $aline['dscp'] = " dscp \"44\" ";
+ break;
+ case 'VA':
+ $aline['dscp'] = " dscp \"44\" ";
+ break;
+ case 'cs1':
+ $aline['dscp'] = " dscp \"8\" ";
+ break;
+ case 'cs2':
+ $aline['dscp'] = " dscp \"16\" ";
+ break;
+ case 'cs3':
+ $aline['dscp'] = " dscp \"24\" ";
+ break;
+ case 'cs4':
+ $aline['dscp'] = " dscp \"32\" ";
+ break;
+ case 'cs5':
+ $aline['dscp'] = " dscp \"40\" ";
+ break;
+ case 'cs6':
+ $aline['dscp'] = " dscp \"48\" ";
+ break;
+ case 'cs7':
+ $aline['dscp'] = " dscp \"56\" ";
+ break;
+ default:
+ $aline['dscp'] = " dscp " . $rule['dscp'] . " ";
+ break;
+ }
+ }
+ if (!empty($rule['vlanprio']) && ($rule['vlanprio'] != "none")) {
+ $aline['vlanprio'] = " ieee8021q-pcp " . $rule['vlanprio'] . " ";
+ }
+ if (!empty($rule['vlanprioset']) && ($rule['vlanprioset'] != "none")) {
+ $aline['vlanprioset'] = " ieee8021q-setpcp " . $rule['vlanprioset'] . " ";
+ }
+ if ($type == "pass") {
+ if (isset($rule['allowopts'])) {
+ $aline['allowopts'] = " allow-opts ";
+ }
+ }
+ $aline['flags'] = "";
+ if ($rule['protocol'] == "tcp") {
+ if (isset($rule['tcpflags_any'])) {
+ $aline['flags'] = "flags any ";
+ } else if (!empty($rule['tcpflags2'])) {
+ $aline['flags'] = "flags ";
+ if (!empty($rule['tcpflags1'])) {
+ $flags1 = explode(",", $rule['tcpflags1']);
+ foreach ($flags1 as $flag1) {
+ // CWR flag needs special treatment
+ if ($flag1[0] == "c") {
+ $aline['flags'] .= "W";
+ } else {
+ $aline['flags'] .= strtoupper($flag1[0]);
+ }
+ }
+ }
+ $aline['flags'] .= "/";
+ if (!empty($rule['tcpflags2'])) {
+ $flags2 = explode(",", $rule['tcpflags2']);
+ foreach ($flags2 as $flag2) {
+ // CWR flag needs special treatment
+ if ($flag2[0] == "c") {
+ $aline['flags'] .= "W";
+ } else {
+ $aline['flags'] .= strtoupper($flag2[0]);
+ }
+ }
+ }
+ $aline['flags'] .= " ";
+ } else {
+ $aline['flags'] = "flags S/SA ";
+ }
+ }
+ if ($type == "pass") {
+ /*
+ * # keep state
+ * works with TCP, UDP, and ICMP.
+ * # modulate state
+ * works only with TCP. pfSense will generate strong Initial Sequence Numbers (ISNs)
+ * for packets matching this rule.
+ * # synproxy state
+ * proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods.
+ * This option includes the functionality of keep state and modulate state combined.
+ * # none
+ * do not use state mechanisms to keep track. this is only useful if your doing advanced
+ * queueing in certain situations. please check the faq.
+ */
+ $noadvoptions = false;
+ if (isset($rule['statetype']) && $rule['statetype'] <> "") {
+ switch ($rule['statetype']) {
+ case "none":
+ $noadvoptions = true;
+ $aline['flags'] .= " no state ";
+ break;
+ case "modulate state":
+ case "synproxy state":
+ if ($rule['protocol'] == "tcp") {
+ $aline['flags'] .= "{$rule['statetype']} ";
+ }
+ break;
+ case "sloppy state":
+ $aline['flags'] .= "keep state ";
+ $rule['sloppy'] = true;
+ break;
+ default:
+ $aline['flags'] .= "{$rule['statetype']} ";
+ break;
+ }
+ } else {
+ $aline['flags'] .= "keep state ";
+ }
+
+ if ($noadvoptions == false && isset($rule['nopfsync'])) {
+ $rule['nopfsync'] = true;
+ }
+
+ if ($noadvoptions == false || $l7_present) {
+ if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
+ (isset($rule['max']) and $rule['max'] <> "") or
+ (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
+ (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
+ ((in_array($rule['protocol'], array("tcp", "tcp/udp"))) and
+ ((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
+ (isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
+ (isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
+ (isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
+ (isset($rule['sloppy'])) or
+ (isset($rule['nopfsync'])) or
+ ($l7_present)) {
+ $aline['flags'] .= "( ";
+ if (isset($rule['sloppy'])) {
+ $aline['flags'] .= "sloppy ";
+ }
+ if (isset($rule['nopfsync'])) {
+ $aline['flags'] .= "no-sync ";
+ }
+ if (isset($rule['source-track']) and $rule['source-track'] <> "") {
+ $aline['flags'] .= "source-track rule ";
+ }
+ if (isset($rule['max']) and $rule['max'] <> "") {
+ $aline['flags'] .= "max " . $rule['max'] . " ";
+ }
+ if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") {
+ $aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
+ }
+ if ((in_array($rule['protocol'], array("tcp", "tcp/udp"))) and
+ (isset($rule['max-src-conn'])) and
+ ($rule['max-src-conn'] <> "")) {
+ $aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
+ }
+ if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") {
+ $aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
+ }
+ if ((in_array($rule['protocol'], array("tcp", "tcp/udp"))) and
+ (isset($rule['statetimeout'])) and
+ ($rule['statetimeout'] <> "")) {
+ $aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
+ }
+ if ((in_array($rule['protocol'], array("tcp", "tcp/udp"))) and
+ (isset($rule['max-src-conn-rate'])) and
+ ($rule['max-src-conn-rate'] <> "") and
+ (isset($rule['max-src-conn-rates'])) and
+ ($rule['max-src-conn-rates'] <> "")) {
+ $aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
+ $aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
+ }
+
+ if (!empty($aline['divert'])) {
+ $aline['flags'] .= "max-packets 8 ";
+ }
+
+ $aline['flags'] .= " ) ";
+ }
+ }
+ }
+ if ($rule['defaultqueue'] <> "") {
+ $aline['queue'] = " queue (".$rule['defaultqueue'];
+ if ($rule['ackqueue'] <> "") {
+ $aline['queue'] .= "," . $rule['ackqueue'];
+ }
+ $aline['queue'] .= ") ";
+ }
+ if ($rule['dnpipe'] <> "") {
+ if (!empty($dummynet_name_list[$rule['dnpipe']])) {
+ if ($dummynet_name_list[$rule['dnpipe']][0] == "?") {
+ $aline['dnpipe'] = " dnqueue( ";
+ $aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']], 1);
+ if ($rule['pdnpipe'] <> "") {
+ $aline['dnpipe'] .= "," . substr($dummynet_name_list[$rule['pdnpipe']], 1);
+ }
+ } else {
+ $aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
+ if ($rule['pdnpipe'] <> "") {
+ $aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
+ }
+ }
+ $aline['dnpipe'] .= ") ";
+ }
+ }
+
+ /* is a time based rule schedule attached? */
+ if (!empty($rule['sched']) && !empty($config['schedules'])) {
+ $aline['schedlabel'] = "";
+ foreach ($config['schedules']['schedule'] as $sched) {
+ if ($sched['name'] == $rule['sched']) {
+ if (!filter_get_time_based_rule_status($sched)) {
+ if (!isset($config['system']['schedule_states'])) {
+ mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
+ }
+ return "# schedule finished - {$rule['descr']}";
+ } else if ($g['debug']) {
+ log_error("[TDR DEBUG] status true -- rule type '$type'");
+ }
+
+ $aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
+ break;
+ }
+ }
+ }
+
+ if (!empty($rule['tracker'])) {
+ $aline['tracker'] = "tracker {$rule['tracker']} ";
+ }
+
+ $line = "";
+ /* exception(s) to a user rules can go here. */
+ /* rules with a gateway or pool should create another rule for routing to vpns */
+ if ((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
+ /* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
+ $negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
+ $line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
+ $aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
+ $negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
+ $aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . filter_negaterule_tracker() . $aline['allowopts'] . $aline['flags'] .
+ $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
+ " label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
+
+ }
+ /* piece together the actual user rule */
+ $line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
+ $aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
+ $aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
+ $aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
+
+ unset($aline);
+
+ return $line;
+}
+
+function filter_rules_generate() {
+ global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
+
+ $fix_rule_label = 'fix_rule_label';
+ $increment_tracker = 'filter_rule_tracker';
+
+ update_filter_reload_status(gettext("Creating default rules"));
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_rules_generate() being called $mt\n";
+ }
+
+ $pptpdcfg = $config['pptpd'];
+
+ $ipfrules = "";
+ $ipfrules .= discover_pkg_rules("pfearly");
+
+ /* relayd */
+ $ipfrules .= "anchor \"relayd/*\"\n";
+ /* OpenVPN user rules from radius */
+ $ipfrules .= "anchor \"openvpn/*\"\n";
+ /* IPsec user rules from radius */
+ $ipfrules .= "anchor \"ipsec/*\"\n";
+ # BEGIN OF firewall rules
+ /* default block logging? */
+ $log = array();
+ if (!isset($config['syslog']['nologdefaultblock'])) {
+ $log['block'] = "log";
+ }
+ if (isset($config['syslog']['nologdefaultpass'])) {
+ $log['pass'] = "log";
+ }
+
+ $saved_tracker = $tracker;
+
+ if (!isset($config['system']['ipv6allow'])) {
+ $ipfrules .= "# Allow IPv6 on loopback\n";
+ $ipfrules .= "pass in {$log['pass']} quick on \$loopback inet6 all tracker {$increment_tracker($tracker)} label \"pass IPv6 loopback\"\n";
+ $ipfrules .= "pass out {$log['pass']} quick on \$loopback inet6 all tracker {$increment_tracker($tracker)} label \"pass IPv6 loopback\"\n";
+ $ipfrules .= "# Block all IPv6\n";
+ $ipfrules .= "block in {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
+ $ipfrules .= "block out {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
+ }
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ if (!isset($config['system']['no_apipa_block'])) {
+ $ipfrules .= <<<EOD
+# block IPv4 link-local. Per RFC 3927, link local "MUST NOT" be forwarded by a routing device,
+# and clients "MUST NOT" send such packets to a router. FreeBSD won't route 169.254./16, but
+# route-to can override that, causing problems such as in redmine #2073
+block in {$log['block']} quick from 169.254.0.0/16 to any tracker {$increment_tracker($tracker)} label "Block IPv4 link-local"
+block in {$log['block']} quick from any to 169.254.0.0/16 tracker {$increment_tracker($tracker)} label "Block IPv4 link-local"
+
+EOD;
+ }
+
+ $ipfrules .= <<<EOD
+#---------------------------------------------------------------------------
+# default deny rules
+#---------------------------------------------------------------------------
+block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
+block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
+block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
+block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
+
+# IPv6 ICMP is not auxilary, it is required for operation
+# See man icmp6(4)
+# 1 unreach Destination unreachable
+# 2 toobig Packet too big
+# 128 echoreq Echo service request
+# 129 echorep Echo service reply
+# 133 routersol Router solicitation
+# 134 routeradv Router advertisement
+# 135 neighbrsol Neighbor solicitation
+# 136 neighbradv Neighbor advertisement
+pass {$log['pass']} quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} tracker {$increment_tracker($tracker)} keep state
+
+# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
+pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
+pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
+pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
+pass in {$log['pass']} quick inet6 proto ipv6-icmp from ff02::/16 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
+pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
+
+# We use the mighty pf, we cannot be fooled.
+block {$log['block']} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)} label "Block traffic from port 0"
+block {$log['block']} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)} label "Block traffic to port 0"
+block {$log['block']} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)} label "Block traffic from port 0"
+block {$log['block']} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)} label "Block traffic to port 0"
+
+# Snort package
+block {$log['block']} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
+block {$log['block']} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
+
+EOD;
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ $ipfrules .= filter_process_carp_rules($log);
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ $ipfrules .= "\n# SSH lockout\n";
+ if (is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
+ $ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port ";
+ $ipfrules .= $config['system']['ssh']['port'];
+ $ipfrules .= " tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
+ } else {
+ if ($config['system']['ssh']['port'] <> "") {
+ $sshport = $config['system']['ssh']['port'];
+ } else {
+ $sshport = 22;
+ }
+ if ($sshport) {
+ $ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port {$sshport} tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
+ }
+ }
+
+ $saved_tracker += 50;
+ $tracker = $saved_tracker;
+
+ $ipfrules .= "\n# webConfigurator lockout\n";
+ if (!$config['system']['webgui']['port']) {
+ if ($config['system']['webgui']['protocol'] == "http") {
+ $webConfiguratorlockoutport = "80";
+ } else {
+ $webConfiguratorlockoutport = "443";
+ }
+ } else {
+ $webConfiguratorlockoutport = $config['system']['webgui']['port'];
+ }
+ if ($webConfiguratorlockoutport) {
+ $ipfrules .= "block in {$log['block']} quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} tracker {$increment_tracker($tracker)} label \"webConfiguratorlockout\"\n";
+ }
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ /*
+ * Support for allow limiting of TCP connections by establishment rate
+ * Useful for protecting against sudden outbursts, etc.
+ */
+ $ipfrules .= "block in {$log['block']} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ /* if captive portal is enabled, ensure that access to this port
+ * is allowed on a locked down interface
+ */
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpcfg) {
+ if (!isset($cpcfg['enable'])) {
+ continue;
+ }
+ $cpinterfaces = explode(",", $cpcfg['interface']);
+ $cpiflist = array();
+ $cpiplist = array();
+ foreach ($cpinterfaces as $cpifgrp) {
+ if (!isset($FilterIflist[$cpifgrp])) {
+ continue;
+ }
+ $tmpif = get_real_interface($cpifgrp);
+ if (!empty($tmpif)) {
+ $cpiflist[] = "{$tmpif}";
+ $cpipm = get_interface_ip($cpifgrp);
+ if (is_ipaddr($cpipm)) {
+ $cpiplist[] = $cpipm;
+ if (!is_array($config['virtualip']) || !is_array($config['virtualip']['vip'])) {
+ continue;
+ }
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if (($vip['interface'] == $cpifgrp) && (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias"))) {
+ $cpiplist[] = $vip['subnet'];
+ }
+ }
+ }
+ }
+ }
+ if (count($cpiplist) > 0 && count($cpiflist) > 0) {
+ $cpinterface = implode(" ", $cpiflist);
+ $cpaddresses = implode(" ", $cpiplist);
+ $listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : 8000 + ($cpcfg['zoneid'] + 1);
+ $listenporthttp = $cpcfg['listenporthttp'] ? $cpcfg['listenporthttp'] : 8000 + $cpcfg['zoneid'];
+ $portalias = $listenporthttps;
+ $portalias .= " {$listenporthttp}";
+ $ipfrules .= "pass in {$log['pass']} quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
+ $ipfrules .= "pass out {$log['pass']} quick on { {$cpinterface} } proto tcp from any to any flags any tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
+ }
+ }
+ }
+
+ $bogontableinstalled = 0;
+ foreach ($FilterIflist as $on => $oc) {
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+
+ if (isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
+ // The DHCPv6 client rules ***MUST BE ABOVE BOGONSV6!*** https://redmine.pfsense.org/issues/3395
+ $ipfrules .= <<<EOD
+# allow our DHCPv6 client out to the {$oc['descr']}
+pass in {$log['pass']} quick on \${$oc['descr']} proto udp from fe80::/10 port = 546 to fe80::/10 port = 546 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
+pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 547 to any port = 546 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
+pass out {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 546 to any port = 547 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client out {$oc['descr']}")}"
+
+EOD;
+ }
+
+ /* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
+ $saved_tracker += 1000;
+ $tracker = $saved_tracker;
+
+ /* block bogon networks */
+ /* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
+ /* file is automatically in cron every 3000 minutes */
+ if (!isset($config['syslog']['nologbogons'])) {
+ $bogonlog = "log";
+ } else {
+ $bogonlog = "";
+ }
+
+ if (isset($config['interfaces'][$on]['blockbogons'])) {
+ $ipfrules .= <<<EOD
+# block bogon networks (IPv4)
+# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
+block in $bogonlog quick on \${$oc['descr']} from <bogons> to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("block bogon IPv4 networks from {$oc['descr']}")}"
+
+EOD;
+
+ if (isset($config['system']['ipv6allow'])) {
+ $ipfrules .= <<<EOD
+# block bogon networks (IPv6)
+# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
+block in $bogonlog quick on \${$oc['descr']} from <bogonsv6> to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("block bogon IPv6 networks from {$oc['descr']}")}"
+
+EOD;
+ }
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+
+ $isbridged = false;
+ if (is_array($config['bridges']['bridged'])) {
+ foreach ($config['bridges']['bridged'] as $oc2) {
+ if (stristr($oc2['members'], $on)) {
+ $isbridged = true;
+ break;
+ }
+ }
+ }
+
+ if ($oc['ip'] && !($isbridged) && isset($oc['spoofcheck'])) {
+ $ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
+ }
+
+ /* block private networks ? */
+ if (!isset($config['syslog']['nologprivatenets'])) {
+ $privnetlog = "log";
+ } else {
+ $privnetlog = "";
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+
+ if (isset($config['interfaces'][$on]['blockpriv'])) {
+ if ($isbridged == false) {
+ $ipfrules .= <<<EOD
+# block anything from private networks on interfaces with the option set
+block in $privnetlog quick on \${$oc['descr']} from 10.0.0.0/8 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 10/8")}"
+block in $privnetlog quick on \${$oc['descr']} from 127.0.0.0/8 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 127/8")}"
+block in $privnetlog quick on \${$oc['descr']} from 172.16.0.0/12 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 172.16/12")}"
+block in $privnetlog quick on \${$oc['descr']} from 192.168.0.0/16 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 192.168/16")}"
+block in $privnetlog quick on \${$oc['descr']} from fc00::/7 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block ULA networks from {$oc['descr']} block fc00::/7")}"
+
+EOD;
+ }
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+
+ switch ($oc['type']) {
+ case "pptp":
+ $ipfrules .= <<<EOD
+# allow PPTP client
+pass in {$log['pass']} on \${$oc['descr']} proto tcp from any to any port = 1723 flags S/SA modulate state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
+pass in {$log['pass']} on \${$oc['descr']} proto gre from any to any keep state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
+
+EOD;
+ break;
+ case "dhcp":
+ $ipfrules .= <<<EOD
+# allow our DHCP client out to the {$oc['descr']}
+pass in {$log['pass']} on \${$oc['descr']} proto udp from any port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
+pass out {$log['pass']} on \${$oc['descr']} proto udp from any port = 68 to any port = 67 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
+# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
+
+EOD;
+
+ break;
+ case "pppoe":
+ case "none":
+ /* XXX: Nothing to do in this case?! */
+ break;
+ default:
+ /* allow access to DHCP server on interfaces */
+ if (isset($config['dhcpd'][$on]['enable'])) {
+ $ipfrules .= <<<EOD
+# allow access to DHCP server on {$oc['descr']}
+pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to 255.255.255.255 port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
+
+EOD;
+ if (is_ipaddrv4($oc['ip'])) {
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to {$oc['ip']} port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
+pass out {$log['pass']} quick on \${$oc['descr']} proto udp from {$oc['ip']} port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
+
+EOD;
+ }
+
+ if (is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
+ $ipfrules .= <<<EOD
+# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
+pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 519 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
+pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 520 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
+
+EOD;
+ }
+
+ }
+ break;
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+ switch ($oc['type6']) {
+ case "6rd":
+ $ipfrules .= <<<EOD
+# allow our proto 41 traffic from the 6RD border relay in
+pass in {$log['pass']} on \${$oc['descr']} proto 41 from {$config['interfaces'][$on]['gateway-6rd']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6rd on {$oc['descr']}")}"
+pass out {$log['pass']} on \${$oc['descr']} proto 41 from any to {$config['interfaces'][$on]['gateway-6rd']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6rd on {$oc['descr']}")}"
+
+EOD;
+ /* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
+ if (0 && is_ipaddrv6($oc['ipv6'])) {
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6rd traffic in for 6rd on {$oc['descr']}")}"
+pass out {$log['pass']} on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6rd traffic out for 6rd on {$oc['descr']}")}"
+
+EOD;
+ }
+ break;
+ case "6to4":
+ if (is_ipaddrv4($oc['ip'])) {
+ $ipfrules .= <<<EOD
+# allow our proto 41 traffic from the 6to4 border relay in
+pass in {$log['pass']} on \${$oc['descr']} proto 41 from any to {$oc['ip']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
+pass out {$log['pass']} on \${$oc['descr']} proto 41 from {$oc['ip']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
+
+EOD;
+ }
+ /* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
+ if (0 && is_ipaddrv6($oc['ipv6'])) {
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
+pass out {$log['pass']} on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
+
+EOD;
+ }
+ break;
+ default:
+ if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) ||
+ (isset($oc['track6-interface'])) ||
+ (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
+ $ipfrules .= <<<EOD
+# allow access to DHCPv6 server on {$oc['descr']}
+# We need inet6 icmp for stateless autoconfig and dhcpv6
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to fe80::/10 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from ff02::/16 to fe80::/10 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+
+EOD;
+ if (is_ipaddrv6($oc['ipv6'])) {
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to {$oc['ipv6']} port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+pass out {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from {$oc['ipv6']} port = 547 to fe80::/10 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
+
+EOD;
+ }
+ }
+ break;
+ }
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+
+ /*
+ * NB: The loopback rules are needed here since the antispoof would take precedence then.
+ * If you ever add the 'quick' keyword to the antispoof rules above move the loopback
+ * rules before them.
+ */
+ $ipfrules .= <<<EOD
+
+# loopback
+pass in {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
+pass out {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
+pass in {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
+pass out {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
+# let out anything from the firewall host itself and decrypted IPsec traffic
+pass out {$log['pass']} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
+pass out {$log['pass']} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
+
+EOD;
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+ foreach ($FilterIflist as $ifdescr => $ifcfg) {
+ if (isset($ifcfg['virtual'])) {
+ continue;
+ }
+
+ $gw = get_interface_gateway($ifdescr);
+ if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
+ $ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$ifcfg['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
+ if (is_array($ifcfg['vips'])) {
+ foreach ($ifcfg['vips'] as $vip) {
+ if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}")) {
+ $ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
+ } else {
+ $ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !" . gen_subnet($vip['ip'], $vip['sn']) . "/{$vip['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
+ }
+ }
+ }
+ }
+
+ $gwv6 = get_interface_gateway_v6($ifdescr);
+ $stf = get_real_interface($ifdescr, "inet6");
+ $pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
+ if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
+ $ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$ifcfg['ipv6']} to !{$ifcfg['ipv6']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
+ if (is_array($ifcfg['vips6'])) {
+ foreach ($ifcfg['vips6'] as $vip) {
+ $ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$vip['ip']} to !{$vip['ip']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
+ }
+ }
+ }
+ }
+
+
+ $saved_tracker += 300;
+ $tracker = $saved_tracker;
+ /* add ipsec interfaces */
+ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
+ $ipfrules .= "pass out {$log['pass']} on \$IPsec all tracker {$increment_tracker($tracker)} tracker {$increment_tracker($tracker)} keep state label \"IPsec internal host to host\"\n";
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+ if (is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
+ $alports = filter_get_antilockout_ports();
+
+ if (count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
+ /* if antilockout is enabled, LAN exists and has
+ * an IP and subnet mask assigned
+ */
+ $lanif = $FilterIflist['lan']['if'];
+ $ipfrules .= <<<EOD
+# make sure the user cannot lock himself out of the webConfigurator or SSH
+pass in {$log['pass']} quick on {$lanif} proto tcp from any to ({$lanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
+
+EOD;
+ } else if (count($config['interfaces']) == 1) {
+ /* single-interface deployment, add to WAN */
+ $wanif = $FilterIflist["wan"]['if'];
+ $ipfrules .= <<<EOD
+# make sure the user cannot lock himself out of the webConfigurator or SSH
+pass in {$log['pass']} quick on {$wanif} proto tcp from any to ({$wanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
+
+EOD;
+ }
+ unset($alports);
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+ /* PPTPd enabled? */
+ if ($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
+ if ($pptpdcfg['mode'] == "server") {
+ $pptpdtarget = get_interface_ip();
+ } else {
+ $pptpdtarget = $pptpdcfg['redir'];
+ }
+ if (is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
+ $ipfrules .= <<<EOD
+# PPTPd rules
+pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto tcp from any to $pptpdtarget port = 1723 tracker {$increment_tracker($tracker)} modulate state label "{$fix_rule_label("allow pptpd {$pptpdtarget}")}"
+pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto gre from any to any tracker {$increment_tracker($tracker)} keep state label "allow gre pptpd"
+
+EOD;
+
+ } else {
+ /* this shouldnt ever happen but instead of breaking the clients ruleset
+ * log an error.
+ */
+ log_error("ERROR! PPTP enabled but could not resolve the \$pptpdtarget");
+ }
+ }
+
+ $saved_tracker += 10;
+ $tracker = $saved_tracker;
+ if (isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
+ foreach ($config['nat']['rule'] as $rule) {
+ if ((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable") &&
+ ($rule['natreflection'] != "disable")) {
+ $ipfrules .= "# NAT Reflection rules\n";
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} inet tagged PFREFLECT tracker {$increment_tracker($tracker)} keep state label "NAT REFLECT: Allow traffic to localhost"
+
+EOD;
+ break;
+ }
+ }
+ }
+
+ if (isset($config['filter']['rule'])) {
+ /* Pre-cache all our rules so we only have to generate them once */
+ $rule_arr1 = array();
+ $rule_arr2 = array();
+ $rule_arr3 = array();
+ $vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
+ /*
+ * NB: The order must be: Floating rules, then interface group and then regular ones.
+ */
+ foreach ($config['filter']['rule'] as $rule) {
+ update_filter_reload_status("Pre-caching {$rule['descr']}...");
+ if (isset ($rule['disabled'])) {
+ continue;
+ }
+
+ if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
+ if (isset($rule['floating'])) {
+ $rule['ipprotocol'] = "inet";
+ $rule_arr1[] = filter_generate_user_rule_arr($rule);
+ $rule['ipprotocol'] = "inet6";
+ $rule_arr1[] = filter_generate_user_rule_arr($rule);
+ } else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
+ $rule['ipprotocol'] = "inet";
+ $rule_arr2[] = filter_generate_user_rule_arr($rule);
+ $rule['ipprotocol'] = "inet6";
+ $rule_arr2[] = filter_generate_user_rule_arr($rule);
+ } else {
+ $rule['ipprotocol'] = "inet";
+ $rule_arr3[] = filter_generate_user_rule_arr($rule);
+ $rule['ipprotocol'] = "inet6";
+ $rule_arr3[] = filter_generate_user_rule_arr($rule);
+ }
+ $rule['ipprotocol'] = "inet46";
+ } else {
+ if (isset($rule['floating'])) {
+ $rule_arr1[] = filter_generate_user_rule_arr($rule);
+ } else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
+ $rule_arr2[] = filter_generate_user_rule_arr($rule);
+ } else {
+ $rule_arr3[] = filter_generate_user_rule_arr($rule);
+ }
+ }
+ if ($rule['sched']) {
+ $time_based_rules = true;
+ }
+ }
+
+ $ipfrules .= "\n# User-defined rules follow\n";
+ $ipfrules .= "\nanchor \"userrules/*\"\n";
+ /* Generate user rule lines */
+ foreach ($rule_arr1 as $rule) {
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+ if (!$rule['rule']) {
+ continue;
+ }
+ $ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
+ }
+ foreach ($rule_arr2 as $rule) {
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+ if (!$rule['rule']) {
+ continue;
+ }
+ $ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
+ }
+ foreach ($rule_arr3 as $rule) {
+ if (isset($rule['disabled'])) {
+ continue;
+ }
+ if (!$rule['rule']) {
+ continue;
+ }
+ $ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
+ }
+ unset($rule_arr1, $rule_arr2, $rule_arr3);
+ }
+
+ $saved_tracker += 100;
+ $tracker = $saved_tracker;
+
+ /* pass traffic between statically routed subnets and the subnet on the
+ * interface in question to avoid problems with complicated routing
+ * topologies
+ */
+ if (isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
+ $ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
+ foreach (get_staticroutes() as $route) {
+ $friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
+ if (is_array($FilterIflist[$friendly])) {
+ $oc = $FilterIflist[$friendly];
+ $routeent = explode("/", $route['network']);
+ unset($sa);
+ if (is_ipaddrv4($oc['ip'])) {
+ $sa = $oc['sa'];
+ $sn = $oc['sn'];
+ }
+ if ($sa && is_ipaddrv4($routeent[0])) {
+ $ipfrules .= <<<EOD
+pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+
+EOD;
+ }
+ unset($sa);
+ if (is_ipaddrv6($oc['ipv6'])) {
+ $sa = $oc['sav6'];
+ $sn = $oc['snv6'];
+ }
+ if ($sa && is_ipaddrv6($routeent[0])) {
+ $ipfrules .= <<<EOD
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
+
+EOD;
+ }
+ }
+ }
+ }
+
+ update_filter_reload_status(gettext("Creating IPsec rules..."));
+ $saved_tracker += 100000;
+ $tracker = $saved_tracker;
+ $ipfrules .= filter_generate_ipsec_rules($log);
+
+ $ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
+
+ $saved_tracker += 200;
+ $tracker = $saved_tracker;
+ update_filter_reload_status("Creating uPNP rules...");
+ if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
+ if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable'])) {
+ $ipfrules .= "anchor \"miniupnpd\"\n";
+ }
+
+ if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
+ $upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
+ foreach ($upnp_interfaces as $upnp_if) {
+ if (is_array($FilterIflist[$upnp_if])) {
+ $oc = $FilterIflist[$upnp_if];
+ unset($sa);
+ if ($oc['ip']) {
+ $sa = $oc['sa'];
+ $sn = $oc['sn'];
+ }
+ if ($sa) {
+ $ipfrules .= <<<EOD
+pass in {$log['pass']} on \${$oc['descr']} proto tcp from {$sa}/{$sn} to 239.255.255.250/32 port 1900 tracker {$increment_tracker($tracker)} keep state label "pass multicast traffic to miniupnpd"
+
+EOD;
+ }
+ }
+ }
+ }
+ }
+
+ return $ipfrules;
+}
+
+function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
+ global $g, $config, $tracker;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_rules_spoofcheck_generate() being called $mt\n";
+ }
+ $ipfrules = "antispoof {$log['block']} for \${$ifcfg['descr']} tracker {$tracker}\n";
+ $tracker++;
+
+ return $ipfrules;
+}
+
+/* COMPAT Function */
+function tdr_install_cron($should_install) {
+ log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
+ filter_tdr_install_cron($should_install);
+}
+
+/****f* filter/filter_tdr_install_cron
+ * NAME
+ * filter_tdr_install_cron
+ * INPUTS
+ * $should_install true if the cron entry should be installed, false
+ * if the entry should be removed if it is present
+ * RESULT
+ * none
+ ******/
+function filter_tdr_install_cron($should_install) {
+ global $config, $g;
+
+ if (platform_booting() == true) {
+ return;
+ }
+
+ if (!is_array($config['cron'])) {
+ $config['cron'] = array();
+ }
+ if (!is_array($config['cron']['item'])) {
+ $config['cron']['item'] = array();
+ }
+
+ $x = 0;
+ $is_installed = false;
+ foreach ($config['cron']['item'] as $item) {
+ if (strstr($item['command'], "filter_configure_sync")) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+
+ switch ($should_install) {
+ case true:
+ if (!$is_installed) {
+ $cron_item = array();
+ $cron_item['minute'] = "0,15,30,45";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/etc/rc.filter_configure_sync";
+ $config['cron']['item'][] = $cron_item;
+ write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
+ configure_cron();
+ }
+ break;
+ case false:
+ if ($is_installed) {
+ unset($config['cron']['item'][$x]);
+ write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
+ configure_cron();
+ }
+ break;
+ }
+}
+
+/****f* filter/filter_get_time_based_rule_status
+ * NAME
+ * filter_get_time_based_rule_status
+ * INPUTS
+ * xml schedule block
+ * RESULT
+ * true/false - true if the rule should be installed
+ ******/
+/*
+ <schedules>
+ <schedule>
+ <name>ScheduleMultipleTime</name>
+ <descr>main descr</descr>
+ <time>
+ <position>0,1,2</position>
+ <hour>0:0-24:0</hour>
+ <desc>time range 2</desc>
+ </time>
+ <time>
+ <position>4,5,6</position>
+ <hour>0:0-24:0</hour>
+ <desc>time range 1</desc>
+ </time>
+ </schedule>
+ </schedules>
+*/
+function filter_get_time_based_rule_status($schedule) {
+
+ /* no schedule? rule should be installed */
+ if (empty($schedule)) {
+ return true;
+ }
+ /*
+ * iterate through time blocks and determine
+ * if the rule should be installed or not.
+ */
+ foreach ($schedule['timerange'] as $timeday) {
+ if (empty($timeday['month'])) {
+ $monthstatus = true;
+ } else {
+ $monthstatus = filter_tdr_month($timeday['month']);
+ }
+ if (empty($timeday['day'])) {
+ $daystatus = true;
+ } else {
+ $daystatus = filter_tdr_day($timeday['day']);
+ }
+ if (empty($timeday['hour'])) {
+ $hourstatus = true;
+ } else {
+ $hourstatus = filter_tdr_hour($timeday['hour']);
+ }
+ if (empty($timeday['position'])) {
+ $positionstatus = true;
+ } else {
+ $positionstatus = filter_tdr_position($timeday['position']);
+ }
+
+ if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function filter_tdr_day($schedule) {
+ global $g;
+
+ if ($g['debug']) {
+ log_error("[TDR DEBUG] filter_tdr_day($schedule)");
+ }
+
+ /*
+ * Calculate day of month.
+ * IE: 29th of may
+ */
+ $date = date("d");
+ $defined_days = explode(",", $schedule);
+ foreach ($defined_days as $dd) {
+ if ($date == $dd) {
+ return true;
+ }
+ }
+ return false;
+}
+function filter_tdr_hour($schedule) {
+ global $g;
+
+ /* $schedule should be a string such as 16:00-19:00 */
+ $tmp = explode("-", $schedule);
+ $starting_time = strtotime($tmp[0]);
+ $ending_time = strtotime($tmp[1]);
+ $now = strtotime("now");
+ if ($g['debug']) {
+ log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
+ }
+ if ($now >= $starting_time and $now < $ending_time) {
+ return true;
+ }
+ return false;
+}
+
+function filter_tdr_position($schedule) {
+ global $g;
+
+ /*
+ * Calculate position, ie: day of week.
+ * Sunday = 7, Monday = 1, Tuesday = 2
+ * Weds = 3, Thursday = 4, Friday = 5,
+ * Saturday = 6
+ * ...
+ */
+ $weekday = date("w");
+ if ($g['debug']) {
+ log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
+ }
+ if ($weekday == 0) {
+ $weekday = 7;
+ }
+ $schedule_days = explode(",", $schedule);
+ foreach ($schedule_days as $day) {
+ if ($day == $weekday) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function filter_tdr_month($schedule) {
+ global $g;
+
+ /*
+ * Calculate month
+ */
+ $todays_month = date("n");
+ $months = explode(",", $schedule);
+ if ($g['debug']) {
+ log_error("[TDR DEBUG] filter_tdr_month($schedule)");
+ }
+ foreach ($months as $month) {
+ if ($month == $todays_month) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function filter_setup_logging_interfaces() {
+ global $config, $FilterIflist;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_setup_logging_interfaces() being called $mt\n";
+ }
+ $rules = "";
+ if (isset($FilterIflist['lan'])) {
+ $rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
+ } else if (isset($FilterIflist['wan'])) {
+ $rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
+ }
+
+ return $rules;
+}
+
+function filter_process_carp_rules($log) {
+ global $g, $config, $tracker;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_process_carp_rules() being called $mt\n";
+ }
+
+ $increment_tracker = 'filter_rule_tracker';
+ $lines = "";
+ /* return if there are no carp configured items */
+ if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
+ $lines .= "block in {$log['block']} quick proto carp from (self) to any tracker {$increment_tracker($tracker)}\n";
+ $lines .= "pass {$log['pass']} quick proto carp tracker {$increment_tracker($tracker)}\n";
+ }
+ return $lines;
+}
+
+/* Generate IPsec Filter Items */
+function filter_generate_ipsec_rules($log = array()) {
+ global $config, $g, $FilterIflist, $tracker;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "filter_generate_ipsec_rules() being called $mt\n";
+ }
+
+ if (isset($config['system']['disablevpnrules'])) {
+ return "\n# VPN Rules not added disabled in System->Advanced.\n";
+ }
+
+ $increment_tracker = 'filter_rule_tracker';
+
+ $ipfrules = "\n# VPN Rules\n";
+ if ((isset($config['ipsec']['enable'])) &&
+ (is_array($config['ipsec']['phase1']))) {
+ /* step through all phase1 entries */
+ foreach ($config['ipsec']['phase1'] as $ph1ent) {
+ $tracker += 10;
+
+ if (isset ($ph1ent['disabled'])) {
+ continue;
+ }
+ /* determine local and remote peer addresses */
+ if (!isset($ph1ent['mobile'])) {
+ if (!function_exists('ipsec_get_phase1_dst')) {
+ require_once("ipsec.inc");
+ }
+ $rgip = ipsec_get_phase1_dst($ph1ent);
+ if (!$rgip) {
+ $ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
+ continue;
+ }
+ } else {
+ $rgip = " any ";
+ }
+ /* Determine best description */
+ if ($ph1ent['descr']) {
+ $descr = $ph1ent['descr'];
+ } else {
+ $descr = $rgip;
+ }
+ /*
+ * Step through all phase2 entries and determine
+ * which protocols are in use with this peer
+ */
+ $prot_used_esp = false;
+ $prot_used_ah = false;
+ if (is_array($config['ipsec']['phase2'])) {
+ foreach ($config['ipsec']['phase2'] as $ph2ent) {
+ /* only evaluate ph2's bound to our ph1 */
+ if ($ph2ent['ikeid'] != $ph1ent['ikeid']) {
+ continue;
+ }
+ if ($ph2ent['protocol'] == 'esp') {
+ $prot_used_esp = true;
+ }
+ if ($ph2ent['protocol'] == 'ah') {
+ $prot_used_ah = true;
+ }
+ }
+ }
+
+ if (strpos($ph1ent['interface'], "_vip")) {
+ $parentinterface = get_configured_carp_interface_list($ph1ent['interface'], '', 'iface');
+ } else {
+ $parentinterface = $ph1ent['interface'];
+ }
+ if (empty($FilterIflist[$parentinterface]['descr'])) {
+ $ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
+ continue;
+ }
+
+ unset($gateway);
+ /* add endpoint routes to correct gateway on interface if the
+ remote endpoint is not on this interface's subnet */
+ if ((isset($ph1ent['mobile']) || is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
+ $parentifsubnet = get_interface_ip($parentinterface) . "/" . get_interface_subnet($parentinterface);
+ if (isset($ph1ent['mobile']) || !ip_in_subnet($rgip, $parentifsubnet)) {
+ $gateway = get_interface_gateway($parentinterface);
+ $interface = $FilterIflist[$parentinterface]['if'];
+
+ $route_to = " route-to ( $interface $gateway ) ";
+ $reply_to = " reply-to ( $interface $gateway ) ";
+ }
+ } else if ((isset($ph1ent['mobile']) || is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
+ $parentifsubnet = get_interface_ipv6($parentinterface) . "/" . get_interface_subnetv6($parentinterface);
+ if (isset($ph1ent['mobile']) || !ip_in_subnet($rgip, $parentifsubnet)) {
+ $gateway = get_interface_gateway_v6($parentinterface);
+ $interface = $FilterIflist[$parentinterface]['if'];
+
+ $route_to = " route-to ( $interface $gateway ) ";
+ $reply_to = " reply-to ( $interface $gateway ) ";
+ }
+ }
+
+ /* Just in case */
+ if ((!is_ipaddr($gateway) || empty($interface))) {
+ $route_to = " ";
+ $reply_to = " ";
+ }
+
+ /* Add rules to allow IKE to pass */
+ $shorttunneldescr = substr($descr, 0, 35);
+ $ipfrules .= <<<EOD
+pass out {$log['pass']} $route_to proto udp from any to {$rgip} port = 500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound isakmp"
+pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound isakmp"
+
+EOD;
+ /* If NAT-T is enabled, add additional rules */
+ if ($ph1ent['nat_traversal'] != "off") {
+ $ipfrules .= <<<EOD
+pass out {$log['pass']} $route_to proto udp from any to {$rgip} port = 4500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound nat-t"
+pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 4500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound nat-t"
+
+EOD;
+ }
+ /* Add rules to allow the protocols in use */
+ if ($prot_used_esp) {
+ $ipfrules .= <<<EOD
+pass out {$log['pass']} $route_to proto esp from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound esp proto"
+pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto esp from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound esp proto"
+
+EOD;
+ }
+ if ($prot_used_ah) {
+ $ipfrules .= <<<EOD
+pass out {$log['pass']} $route_to proto ah from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound ah proto"
+pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto ah from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound ah proto"
+
+EOD;
+ }
+ }
+ }
+ return($ipfrules);
+}
+
+function discover_pkg_rules($ruletype) {
+ global $config, $g, $aliases;
+
+ /* Bail if there is no pkg directory, or if the package files might be out of sync. */
+ if (!is_dir("/usr/local/pkg") || file_exists('/conf/needs_package_sync')) {
+ return "";
+ }
+
+ $rules = "";
+ $files = glob("/usr/local/pkg/*.inc");
+ foreach ($files as $pkg_inc) {
+ update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
+ $pkg = basename($pkg_inc, ".inc");
+ $pkg_generate_rules = "{$pkg}_generate_rules";
+ if (!function_exists($pkg_generate_rules)) {
+ require_once($pkg_inc);
+ }
+ if (function_exists($pkg_generate_rules)) {
+ update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
+ $tmprules = $pkg_generate_rules("$ruletype");
+ file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
+ $status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
+ if ($status <> 0) {
+ $errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
+ log_error($errorrules);
+ file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
+ continue;
+ }
+ $rules .= $tmprules;
+ }
+ }
+ return $rules;
+}
+
+function filter_get_antilockout_ports($wantarray = false) {
+ global $config;
+
+ $lockoutports = array();
+ $guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
+ $guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
+ $lockoutports[] = $guiport;
+
+ if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80")) {
+ $lockoutports[] = "80";
+ }
+
+ if (isset($config['system']['enablesshd'])) {
+ $lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
+ }
+
+ if ($wantarray) {
+ return $lockoutports;
+ } else {
+ return implode(" ", $lockoutports);
+ }
+
+}
+
+?>
diff --git a/src/etc/inc/filter_log.inc b/src/etc/inc/filter_log.inc
new file mode 100644
index 0000000..999d81a
--- /dev/null
+++ b/src/etc/inc/filter_log.inc
@@ -0,0 +1,441 @@
+<?php
+/* $Id$ */
+/*
+ filter_log.inc
+ part of pfSesne by Scott Ullrich
+ originally based on m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2009 Jim Pingle <myfirstname>@<mylastname>.org
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ pfSense_BUILDER_BINARIES: /usr/sbin/fifolog_reader /usr/bin/tail /usr/local/sbin/clog
+ pfSense_MODULE: filter
+*/
+
+require 'config.inc';
+
+global $buffer_rules_rdr, $buffer_rules_normal;
+$buffer_rules_rdr = array();
+$buffer_rules_normal = array();
+
+/* format filter logs */
+function conv_log_filter($logfile, $nentries, $tail = 50, $filtertext = "", $filterinterface = null) {
+ global $config, $g;
+
+ /* Make sure this is a number before using it in a system call */
+ if (!(is_numeric($tail))) {
+ return;
+ }
+
+ if ($filtertext) {
+ $tail = 5000;
+ }
+
+ /* Always do a reverse tail, to be sure we're grabbing the 'end' of the log. */
+ $logarr = "";
+
+ if (isset($config['system']['usefifolog'])) {
+ exec("/usr/sbin/fifolog_reader " . escapeshellarg($logfile) . " | /usr/bin/grep 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr);
+ } else {
+ exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . " | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/grep 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr);
+ }
+
+ $filterlog = array();
+ $counter = 0;
+
+ $filterinterface = strtoupper($filterinterface);
+ foreach ($logarr as $logent) {
+ if ($counter >= $nentries) {
+ break;
+ }
+
+ $flent = parse_filter_line($logent);
+ if (!$filterinterface || ($filterinterface == $flent['interface'])) {
+ if ((($flent != "") && (!is_array($filtertext)) && (match_filter_line ($flent, $filtertext))) ||
+ (($flent != "") && (is_array($filtertext)) && (match_filter_field($flent, $filtertext)))) {
+ $counter++;
+ $filterlog[] = $flent;
+ }
+ }
+ }
+ /* Since the lines are in reverse order, flip them around if needed based on the user's preference */
+ return isset($config['syslog']['reverse']) ? $filterlog : array_reverse($filterlog);
+}
+
+function escape_filter_regex($filtertext) {
+ /* If the caller (user) has not already put a backslash before a slash, to escape it in the regex, */
+ /* then this will do it. Take out any "\/" already there, then turn all ordinary "/" into "\/". */
+ return str_replace('/', '\/', str_replace('\/', '/', $filtertext));
+}
+
+function match_filter_line($flent, $filtertext = "") {
+ if (!$filtertext) {
+ return true;
+ }
+ $filtertext = escape_filter_regex(str_replace(' ', '\s+', $filtertext));
+ return @preg_match("/{$filtertext}/i", implode(" ", array_values($flent)));
+}
+
+function match_filter_field($flent, $fields) {
+ foreach ($fields as $key => $field) {
+ if ($field == "All") {
+ continue;
+ }
+ if ((strpos($field, '!') === 0)) {
+ $field = substr($field, 1);
+ if (strtolower($key) == 'act') {
+ if (in_arrayi($flent[$key], explode(" ", $field))) {
+ return false;
+ }
+ } else {
+ $field_regex = escape_filter_regex($field);
+ if (@preg_match("/{$field_regex}/i", $flent[$key])) {
+ return false;
+ }
+ }
+ } else {
+ if (strtolower($key) == 'act') {
+ if (!in_arrayi($flent[$key], explode(" ", $field))) {
+ return false;
+ }
+ } else {
+ $field_regex = escape_filter_regex($field);
+ if (!@preg_match("/{$field_regex}/i", $flent[$key])) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// Case Insensitive in_array function
+function in_arrayi($needle, $haystack) {
+ return in_array(strtolower($needle), array_map('strtolower', $haystack));
+}
+
+function parse_filter_line($line) {
+ global $config, $g;
+
+ $flent = array();
+ $log_split = "";
+
+ if (!preg_match("/(.*)\s(.*)\sfilterlog:\s(.*)$/", $line, $log_split)) {
+ return "";
+ }
+
+ list($all, $flent['time'], $host, $rule) = $log_split;
+
+ $rule_data = explode(",", $rule);
+ $field = 0;
+
+ $flent['rulenum'] = $rule_data[$field++];
+ $flent['subrulenum'] = $rule_data[$field++];
+ $flent['anchor'] = $rule_data[$field++];
+ $flent['tracker'] = $rule_data[$field++];
+ $flent['realint'] = $rule_data[$field++];
+ $flent['interface'] = convert_real_interface_to_friendly_descr($flent['realint']);
+ $flent['reason'] = $rule_data[$field++];
+ $flent['act'] = $rule_data[$field++];
+ $flent['direction'] = $rule_data[$field++];
+ $flent['version'] = $rule_data[$field++];
+
+ if ($flent['version'] == '4' || $flent['version'] == '6') {
+ if ($flent['version'] == '4') {
+ $flent['tos'] = $rule_data[$field++];
+ $flent['ecn'] = $rule_data[$field++];
+ $flent['ttl'] = $rule_data[$field++];
+ $flent['id'] = $rule_data[$field++];
+ $flent['offset'] = $rule_data[$field++];
+ $flent['flags'] = $rule_data[$field++];
+ $flent['protoid'] = $rule_data[$field++];
+ $flent['proto'] = strtoupper($rule_data[$field++]);
+ } else {
+ $flent['class'] = $rule_data[$field++];
+ $flent['flowlabel'] = $rule_data[$field++];
+ $flent['hlim'] = $rule_data[$field++];
+ $flent['proto'] = $rule_data[$field++];
+ $flent['protoid'] = $rule_data[$field++];
+ }
+
+ $flent['length'] = $rule_data[$field++];
+ $flent['srcip'] = $rule_data[$field++];
+ $flent['dstip'] = $rule_data[$field++];
+
+ if ($flent['protoid'] == '6' || $flent['protoid'] == '17') { // TCP or UDP
+ $flent['srcport'] = $rule_data[$field++];
+ $flent['dstport'] = $rule_data[$field++];
+
+ $flent['src'] = $flent['srcip'] . ':' . $flent['srcport'];
+ $flent['dst'] = $flent['dstip'] . ':' . $flent['dstport'];
+
+ $flent['datalen'] = $rule_data[$field++];
+ if ($flent['protoid'] == '6') { // TCP
+ $flent['tcpflags'] = $rule_data[$field++];
+ $flent['seq'] = $rule_data[$field++];
+ $flent['ack'] = $rule_data[$field++];
+ $flent['window'] = $rule_data[$field++];
+ $flent['urg'] = $rule_data[$field++];
+ $flent['options'] = explode(";", $rule_data[$field++]);
+ }
+ } else if ($flent['protoid'] == '1') { // ICMP
+ $flent['src'] = $flent['srcip'];
+ $flent['dst'] = $flent['dstip'];
+
+ $flent['icmp_type'] = $rule_data[$field++];
+
+ switch ($flent['icmp_type']) {
+ case "request":
+ case "reply":
+ $flent['icmp_id'] = $rule_data[$field++];
+ $flent['icmp_seq'] = $rule_data[$field++];
+ break;
+ case "unreachproto":
+ $flent['icmp_dstip'] = $rule_data[$field++];
+ $flent['icmp_protoid'] = $rule_data[$field++];
+ break;
+ case "unreachport":
+ $flent['icmp_dstip'] = $rule_data[$field++];
+ $flent['icmp_protoid'] = $rule_data[$field++];
+ $flent['icmp_port'] = $rule_data[$field++];
+ break;
+ case "unreach":
+ case "timexceed":
+ case "paramprob":
+ case "redirect":
+ case "maskreply":
+ $flent['icmp_descr'] = $rule_data[$field++];
+ break;
+ case "needfrag":
+ $flent['icmp_dstip'] = $rule_data[$field++];
+ $flent['icmp_mtu'] = $rule_data[$field++];
+ break;
+ case "tstamp":
+ $flent['icmp_id'] = $rule_data[$field++];
+ $flent['icmp_seq'] = $rule_data[$field++];
+ break;
+ case "tstampreply":
+ $flent['icmp_id'] = $rule_data[$field++];
+ $flent['icmp_seq'] = $rule_data[$field++];
+ $flent['icmp_otime'] = $rule_data[$field++];
+ $flent['icmp_rtime'] = $rule_data[$field++];
+ $flent['icmp_ttime'] = $rule_data[$field++];
+ break;
+ default :
+ $flent['icmp_descr'] = $rule_data[$field++];
+ break;
+ }
+
+ } else if ($flent['protoid'] == '2') { // IGMP
+ $flent['src'] = $flent['srcip'];
+ $flent['dst'] = $flent['dstip'];
+ } else if ($flent['protoid'] == '112') { // CARP
+ $flent['type'] = $rule_data[$field++];
+ $flent['ttl'] = $rule_data[$field++];
+ $flent['vhid'] = $rule_data[$field++];
+ $flent['version'] = $rule_data[$field++];
+ $flent['advskew'] = $rule_data[$field++];
+ $flent['advbase'] = $rule_data[$field++];
+ }
+ } else {
+ if ($g['debug']) {
+ log_error(sprintf(gettext("There was a error parsing rule number: %s. Please report to mailing list or forum."), $flent['rulenum']));
+ }
+ return "";
+ }
+
+ /* If there is a src, a dst, and a time, then the line should be usable/good */
+ if (!((trim($flent['src']) == "") || (trim($flent['dst']) == "") || (trim($flent['time']) == ""))) {
+ return $flent;
+ } else {
+ if ($g['debug']) {
+ log_error(sprintf(gettext("There was a error parsing rule: %s. Please report to mailing list or forum."), $errline));
+ }
+ return "";
+ }
+}
+
+function get_port_with_service($port, $proto) {
+ if (!$port) {
+ return '';
+ }
+
+ $service = getservbyport($port, $proto);
+ $portstr = "";
+ if ($service) {
+ $portstr = sprintf('<span title="' . gettext('Service %1$s/%2$s: %3$s') . '">' . htmlspecialchars($port) . '</span>', $port, $proto, $service);
+ } else {
+ $portstr = htmlspecialchars($port);
+ }
+ return ':' . $portstr;
+}
+
+function find_rule_by_number($rulenum, $trackernum, $type="block") {
+ global $g;
+
+ /* Passing arbitrary input to grep could be a Very Bad Thing(tm) */
+ if (!is_numeric($rulenum) || !is_numeric($trackernum) || !in_array($type, array('pass', 'block', 'match', 'rdr'))) {
+ return;
+ }
+
+ if ($trackernum == "0") {
+ $lookup_pattern = "^@{$rulenum}\([0-9]+\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
+ } else {
+ $lookup_pattern = "^@[0-9]+\({$trackernum}\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
+ }
+
+ /* At the moment, miniupnpd is the only thing I know of that
+ generates logging rdr rules */
+ unset($buffer);
+ if ($type == "rdr") {
+ $_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | /usr/bin/egrep " . escapeshellarg("^@{$rulenum}"), $buffer);
+ } else {
+ if (file_exists("{$g['tmp_path']}/rules.debug")) {
+ $_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
+ } else {
+ $_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
+ }
+ }
+ if (is_array($buffer)) {
+ return $buffer[0];
+ }
+
+ return "";
+}
+
+function buffer_rules_load() {
+ global $g, $buffer_rules_rdr, $buffer_rules_normal;
+ unset($buffer, $buffer_rules_rdr, $buffer_rules_normal);
+ /* Redeclare globals after unset to work around PHP */
+ global $buffer_rules_rdr, $buffer_rules_normal;
+ $buffer_rules_rdr = array();
+ $buffer_rules_normal = array();
+
+ $_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
+ if (is_array($buffer)) {
+ foreach ($buffer as $line) {
+ list($key, $value) = explode (" ", $line, 2);
+ $buffer_rules_rdr[$key] = $value;
+ }
+ }
+ unset($buffer, $_gb);
+ if (file_exists("{$g['tmp_path']}/rules.debug")) {
+ $_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]' | /usr/bin/egrep -v '^@[0-9]+\([0-9]+\)[[:space:]](nat|rdr|binat|no|scrub)'", $buffer);
+ } else {
+ $_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]'", $buffer);
+ }
+
+ if (is_array($buffer)) {
+ foreach ($buffer as $line) {
+ list($key, $value) = explode (" ", $line, 2);
+ # pfctl rule number output with tracker number: @dd(dddddddddd)
+ $matches = array();
+ if (preg_match('/\@(?P<rulenum>\d+)\((?<trackernum>\d+)\)/', $key, $matches) == 1) {
+ if ($matches['trackernum'] > 0) {
+ $key = $matches['trackernum'];
+ } else {
+ $key = "@{$matches['rulenum']}";
+ }
+ }
+ $buffer_rules_normal[$key] = $value;
+ }
+ }
+ unset($_gb, $buffer);
+}
+
+function buffer_rules_clear() {
+ unset($GLOBALS['buffer_rules_normal']);
+ unset($GLOBALS['buffer_rules_rdr']);
+}
+
+function find_rule_by_number_buffer($rulenum, $trackernum, $type) {
+ global $g, $buffer_rules_rdr, $buffer_rules_normal;
+
+ if ($trackernum == "0") {
+ $lookup_key = "@{$rulenum}";
+ } else {
+ $lookup_key = $trackernum;
+ }
+
+ if ($type == "rdr") {
+ $ruleString = $buffer_rules_rdr[$lookup_key];
+ //TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
+ $rulename = substr($ruleString, 0, 30);
+ } else {
+ $ruleString = $buffer_rules_normal[$lookup_key];
+ list(,$rulename,) = explode("\"", $ruleString);
+ $rulename = str_replace("USER_RULE: ", '<img src="/themes/' . $g['theme'] . '/images/icons/icon_frmfld_user.png" width="11" height="12" title="USER_RULE" alt="USER_RULE"/> ', $rulename);
+ }
+ return "{$rulename} ({$lookup_key})";
+}
+
+function find_action_image($action) {
+ global $g;
+ if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr")) {
+ return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
+ } else if (strstr(strtolower($action), "r")) {
+ return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
+ } else {
+ return "/themes/{$g['theme']}/images/icons/icon_block.gif";
+ }
+}
+
+/* AJAX specific handlers */
+function handle_ajax($nentries, $tail = 50) {
+ global $config;
+ if ($_GET['lastsawtime'] or $_POST['lastsawtime']) {
+ global $filter_logfile, $filterent;
+ if ($_GET['lastsawtime']) {
+ $lastsawtime = $_GET['lastsawtime'];
+ }
+ if ($_POST['lastsawtime']) {
+ $lastsawtime = $_POST['lastsawtime'];
+ }
+ /* compare lastsawrule's time stamp to filter logs.
+ * afterwards return the newer records so that client
+ * can update AJAX interface screen.
+ */
+ $new_rules = "";
+ $filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
+ /* We need this to always be in forward order for the AJAX update to work properly */
+ $filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
+ foreach ($filterlog as $log_row) {
+ $row_time = strtotime($log_row['time']);
+ $img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
+ if ($row_time > $lastsawtime) {
+ if ($log_row['proto'] == "TCP") {
+ $log_row['proto'] .= ":{$log_row['tcpflags']}";
+ }
+
+ $img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
+ $new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['srcip']}||{$log_row['srcport']}||{$log_row['dstip']}||{$log_row['dstport']}||{$log_row['proto']}||{$log_row['version']}||" . time() . "||\n";
+ }
+ }
+ echo $new_rules;
+ exit;
+ }
+}
+
+?>
diff --git a/src/etc/inc/functions.inc b/src/etc/inc/functions.inc
new file mode 100644
index 0000000..2c8f4c8
--- /dev/null
+++ b/src/etc/inc/functions.inc
@@ -0,0 +1,158 @@
+<?php
+/* $Id$ */
+/*
+ functions.inc
+ Copyright (C) 2004-2006 Scott Ullrich
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_MODULE: utils
+
+*/
+
+/* BEGIN compatibility goo with HEAD */
+if (!function_exists("gettext")) {
+ function gettext($text) {
+ return $text;
+ }
+}
+
+if (!function_exists("pfSenseHeader")) {
+ /****f* pfsense-utils/pfSenseHeader
+ * NAME
+ * pfSenseHeader
+ * INPUTS
+ * none
+ * RESULT
+ * Javascript header change or browser Location:
+ ******/
+ function pfSenseHeader($text) {
+ global $_SERVER;
+ if (isAjax()) {
+ if ($_SERVER['HTTPS'] == "on") {
+ $protocol = "https";
+ } else {
+ $protocol = "http";
+ }
+
+ $port = ":{$_SERVER['SERVER_PORT']}";
+ if ($_SERVER['SERVER_PORT'] == "80" && $protocol == "http") {
+ $port = "";
+ }
+ if ($_SERVER['SERVER_PORT'] == "443" && $protocol == "https") {
+ $port = "";
+ }
+ $complete_url = "{$protocol}://{$_SERVER['SERVER_NAME']}{$port}/{$text}";
+ echo "\ndocument.location.href = '{$complete_url}';\n";
+ } else {
+ header("Location: $text");
+ }
+ }
+}
+/* END compatibility goo with HEAD */
+
+/*fetch menu notices function*/
+if (!function_exists("get_menu_messages")) {
+ function get_menu_messages() {
+ global $g, $config;
+ if (are_notices_pending()) {
+ $notices = get_notices();
+ $requests = array();
+
+ ## Get Query Arguments from URL ###
+ foreach ($_REQUEST as $key => $value) {
+ if ($key != "PHPSESSID") {
+ $requests[] = $key.'='.$value;
+ }
+ }
+ if (is_array($requests)) {
+ $request_string = implode("&", $requests);
+ }
+
+ if (is_array($notices)) {
+ $notice_msgs = "<table colspan=\'6\' id=\'notice_table\'>";
+ $alert_style="style=\'color:#ffffff; filter:Glow(color=#ff0000, strength=12);\' ";
+ $notice = "<a href=\'#\' onclick=notice_action(\'acknowledge\',\'all\');domTT_close(this); {$alert_style}>".gettext("Acknowledge All Notices")."</a>";
+ $alert_link="title=\'".gettext("Click to Acknowledge")."\' {$alert_style}";
+ $domtt_width=500;
+ foreach ($notices as $key => $value) {
+ $date = date("m-d-y H:i:s", $key);
+ $noticemsg = ($value['notice'] != "" ? $value['notice'] : $value['id']);
+ $noticemsg = preg_replace("/(\"|\'|\n|<.?\w+>)/i", "", $noticemsg);
+ if ((strlen($noticemsg)* 8) > $domtt_width) {
+ $domtt_width=(strlen($noticemsg) *8);
+ }
+ if ((strlen($noticemsg)* 8) > 900) {
+ $domtt_width= 900;
+ }
+ $alert_action ="onclick=notice_action(\'acknowledge\',\'{$key}\');domTT_close(this);jQuery(this).parent().parent().remove();";
+ $notice_msgs .= "<tr><td valign=\'top\' width=\'120\'><a href=\'#\' {$alert_link} {$alert_action}>{$date}</a></td><td valign=\'top\'><a href=\'#\' {$alert_link} {$alert_action}>[ ".htmlspecialchars($noticemsg)."]</a></td></tr>";
+ }
+ $notice_msgs .="</table>";
+
+ $domtt= "onclick=\"domTT_activate(this, event, 'caption', '{$notice}','content', '<br />{$notice_msgs}', 'trail', false, 'delay', 0, 'fade', 'both', 'fadeMax', 93, 'styleClass', 'niceTitle','width','{$domtt_width}','y',5,'type', 'sticky');\"";
+ $menu_messages="<div id='alerts'>\n";
+ if (count($notices) == 1) {
+ $msg= sprintf("%1$02d", count($notices)) . " " . gettext("unread notice");
+ } else {
+ $msg= sprintf("%1$02d", count($notices)) . " " . gettext("unread notices");
+ }
+ $menu_messages .= "<div id='marquee-text' style='z-index:1001;'><a href='#' {$domtt}><b> .:. {$msg} .:. </b></a></div>\n";
+ $menu_messages .= "</div>\n";
+ }
+ } else {
+ $menu_messages = '<div id="hostname">';
+ $menu_messages .= $config['system']['hostname'] . "." . $config['system']['domain'];
+ $menu_messages .= '</div>';
+ }
+ return ($menu_messages);
+ }
+}
+
+if (!function_exists("dom_title")) {
+ function dom_title($title_msg, $width=NULL) {
+ $width=preg_replace("/\D+/", "", $width);
+ if (!empty($width)) {
+ $width=",'width',$width";
+ }
+ if (!empty($title_msg)) {
+ $title_msg=preg_replace("/\s+/", " ", $title_msg);
+ $title_msg=preg_replace("/'/", "\'", $title_msg);
+ return "onmouseout=\"this.style.color = ''; domTT_mouseout(this, event);\" onmouseover=\"domTT_activate(this, event, 'content', '{$title_msg}', 'trail', true, 'delay', 250, 'fade', 'both', 'fadeMax', 93, 'styleClass', 'niceTitle' $width);\"";
+ }
+ }
+}
+/* include all configuration functions */
+require_once("interfaces.inc");
+require_once("gwlb.inc");
+require_once("services.inc");
+require_once("pfsense-utils.inc");
+require_once("certs.inc");
+require_once("system.inc");
+require_once("vslb.inc");
+
+?>
diff --git a/src/etc/inc/globals.inc b/src/etc/inc/globals.inc
new file mode 100644
index 0000000..f7fe0fc
--- /dev/null
+++ b/src/etc/inc/globals.inc
@@ -0,0 +1,195 @@
+<?php
+/* $Id$ */
+/*
+ globals.inc
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004-2010 Scott Ullrich
+
+ Originally Part of m0n0wall
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_MODULE: utils
+
+*/
+
+global $g;
+$g = array(
+ "base_packages" => "siproxd",
+ "event_address" => "unix:///var/run/check_reload_status",
+ "factory_shipped_username" => "admin",
+ "factory_shipped_password" => "pfsense",
+ "upload_path" => "/root",
+ "dhcpd_chroot_path" => "/var/dhcpd",
+ "unbound_chroot_path" => "/var/unbound",
+ "var_path" => "/var",
+ "varrun_path" => "/var/run",
+ "varetc_path" => "/var/etc",
+ "vardb_path" => "/var/db",
+ "varlog_path" => "/var/log",
+ "etc_path" => "/etc",
+ "tmp_path" => "/tmp",
+ "conf_path" => "/conf",
+ "conf_default_path" => "/conf.default",
+ "cf_path" => "/cf",
+ "cf_conf_path" => "/cf/conf",
+ "www_path" => "/usr/local/www",
+ "xml_rootobj" => "pfsense",
+ "admin_group" => "admins",
+ "product_name" => "pfSense",
+ "product_version" => trim(file_get_contents("/etc/version"), " \n"),
+ "product_copyright" => "Electric Sheep Fencing LLC",
+ "product_copyright_url" => "http://www.electricsheepfencing.com",
+ "product_copyright_years" => "2004 - ".date("Y"),
+ "product_website" => "www.pfsense.org",
+ "product_website_footer" => "https://www.pfsense.org/?gui22",
+ "product_email" => "coreteam@pfsense.org",
+ "hideplatform" => false,
+ "hidedownloadbackup" => false,
+ "hidebackupbeforeupgrade" => false,
+ "disablethemeselection" => false,
+ "disablehelpmenu" => false,
+ "disablehelpicon" => false,
+ "disablecrashreporter" => false,
+ "crashreporterurl" => "https://crashreporter.pfsense.org/crash_reporter.php",
+ "debug" => false,
+ "latest_config" => "11.9",
+ "nopkg_platforms" => array("cdrom"),
+ "minimum_ram_warning" => "101",
+ "minimum_ram_warning_text" => "128 MB",
+ "wan_interface_name" => "wan",
+ "xmlrpcbaseurl" => "https://packages.pfsense.org",
+ "captiveportal_path" => "/usr/local/captiveportal",
+ "captiveportal_element_path" => "/var/db/cpelements",
+ "captiveportal_element_sizelimit" => 1048576,
+ "xmlrpcpath" => "/xmlrpc.php",
+ "embeddedbootupslice" => "/dev/ad0a",
+ "services_dhcp_server_enable" => true,
+ "wireless_regex" => "/^(ndis|wi|ath|an|ral|ural|iwi|wlan|rum|run|bwn|zyd|mwl|bwi|ipw|iwn|malo|uath|upgt|urtw|wpi)/",
+ "help_base_url" => "/help.php",
+ "pkg_prefix" => "pfSense-pkg-"
+);
+
+/* IP TOS flags */
+$iptos = array("lowdelay", "throughput", "reliability");
+
+/* TCP flags */
+$tcpflags = array("syn", "ack", "fin", "rst", "psh", "urg", "ece", "cwr");
+
+if (file_exists("/etc/platform")) {
+ $arch = php_uname("m");
+
+ if (strstr($g['product_version'], "-RELEASE")) {
+ /* This is only necessary for RELEASE */
+ $arch = ($arch == "i386") ? "" : '/' . $arch;
+ /* Full installs and NanoBSD use the same update directory and manifest in 2.x */
+ $g['update_url']="https://updates.pfsense.org/_updaters{$arch}";
+ $g['update_manifest']="https://updates.pfsense.org/manifest";
+ } else {
+ /* Full installs and NanoBSD use the same update directory and manifest in 2.x */
+ $g['update_url']="https://snapshots.pfsense.org/FreeBSD_releng/10.1/{$arch}/pfSense_HEAD/.updaters/";
+ $g['update_manifest']="https://updates.pfSense.org/manifest";
+ }
+
+ $g['platform'] = trim(file_get_contents("/etc/platform"));
+ if ($g['platform'] == "nanobsd") {
+ $g['firmware_update_text']="pfSense-*.img.gz";
+ $g['hidedownloadbackup'] = true;
+ $g['hidebackupbeforeupgrade'] = true;
+
+ } else {
+ $g['firmware_update_text']="pfSense-*.tgz";
+ }
+}
+
+/* Default sysctls */
+$sysctls = array("net.inet.ip.portrange.first" => "1024",
+ "net.inet.tcp.blackhole" => "2",
+ "net.inet.udp.blackhole" => "1",
+ "net.inet.ip.random_id" => "1",
+ "net.inet.tcp.drop_synfin" => "1",
+ "net.inet.ip.redirect" => "1",
+ "net.inet6.ip6.redirect" => "1",
+ "net.inet6.ip6.use_tempaddr" => "0",
+ "net.inet6.ip6.prefer_tempaddr" => "0",
+ "net.inet.tcp.syncookies" => "1",
+ "net.inet.tcp.recvspace" => "65228",
+ "net.inet.tcp.sendspace" => "65228",
+ "net.inet.ip.fastforwarding" => "0",
+ "net.inet.tcp.delayed_ack" => "0",
+ "net.inet.udp.maxdgram" => "57344",
+ "net.link.bridge.pfil_onlyip" => "0",
+ "net.link.bridge.pfil_member" => "1",
+ "net.link.bridge.pfil_bridge" => "0",
+ "net.link.tap.user_open" => "1",
+ "kern.randompid" => "347",
+ "net.inet.ip.intr_queue_maxlen" => "1000",
+ "hw.syscons.kbd_reboot" => "0",
+ "net.inet.tcp.log_debug" => "0",
+ "net.inet.tcp.tso" => "1",
+ "net.inet.icmp.icmplim" => "0",
+ "vfs.read_max" => "32",
+ "kern.ipc.maxsockbuf" => "4262144",
+ "net.inet.ip.process_options" => 0,
+ "kern.random.sys.harvest.interrupt" => 0,
+ "kern.random.sys.harvest.point_to_point" => 0,
+ "kern.random.sys.harvest.ethernet" => 0,
+ "net.route.netisr_maxqlen" => 1024,
+ "net.inet.udp.checksum" => 1,
+ "net.bpf.zerocopy_enable" => 1,
+ "net.inet.icmp.reply_from_interface" => 1,
+ "net.inet6.ip6.rfc6204w3" => 1,
+ "net.enc.out.ipsec_bpf_mask" => "0x0001",
+ "net.enc.out.ipsec_filter_mask" => "0x0001",
+ "net.enc.in.ipsec_bpf_mask" => "0x0002",
+ "net.enc.in.ipsec_filter_mask" => "0x0002",
+ "net.key.preferred_oldsa" => "0",
+ "net.inet.carp.senderr_demotion_factor" => 0, /* Do not demote CARP for interface send errors */
+ "net.pfsync.carp_demotion_factor" => 0 /* Do not demote CARP for pfsync errors */
+);
+
+/* Include override values for the above if needed. If the file doesn't exist, don't try to load it. */
+if (file_exists("/etc/inc/globals_override.inc")) {
+ @include("globals_override.inc");
+}
+
+function platform_booting($on_console = false) {
+ global $g;
+
+ if ($g['booting'] || file_exists("{$g['varrun_path']}/booting")) {
+ if ($on_console == false || php_sapi_name() != 'fpm-fcgi') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+if (file_exists("{$g['cf_conf_path']}/enableserial_force")) {
+ $g['enableserial_force'] = true;
+}
+
+$config_parsed = false;
+
+?>
diff --git a/src/etc/inc/gmirror.inc b/src/etc/inc/gmirror.inc
new file mode 100644
index 0000000..9e26dfb
--- /dev/null
+++ b/src/etc/inc/gmirror.inc
@@ -0,0 +1,342 @@
+<?php
+/*
+ gmirror.inc
+ Copyright (C) 2009-2014 Jim Pingle
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+global $balance_methods;
+$balance_methods = array("load", "prefer", "round-robin", "split");
+
+/* Create a status array for each mirror and its disk components. */
+function gmirror_get_status() {
+ $status = "";
+ exec("/sbin/gmirror status -s", $status);
+ $mirrors = array();
+
+ /* Empty output = no mirrors found */
+ if (count($status) > 0) {
+ /* Loop through gmirror status output. */
+ foreach ($status as $line) {
+ /* Split the line by whitespace */
+ $all = preg_split("/[\s\t]+/", trim($line), 3);
+ if (count($all) == 3) {
+ /* If there are three items on a line, it is mirror name, status, and component */
+ $currentmirror = basename($all[0]);
+ $mirrors[$currentmirror]['name'] = basename($all[0]);
+ $mirrors[$currentmirror]['status'] = $all[1];
+ if (!is_array($mirrors[$currentmirror]['components'])) {
+ $mirrors[$currentmirror]['components'] = array();
+ }
+ $mirrors[$currentmirror]['components'][] = $all[2];
+ }
+ }
+ }
+ /* Return an hash of mirrors and components */
+ return $mirrors;
+}
+
+/* Get only status word for a single mirror. */
+function gmirror_get_status_single($mirror) {
+ $status = "";
+ $mirror_status = gmirror_get_status();
+ return $mirror_status[$mirror]['status'];
+}
+
+/* Generate an HTML formatted status for mirrors and disks in a small format for the widget */
+function gmirror_html_status() {
+ $mirrors = gmirror_get_status();
+ $output = "";
+ if (count($mirrors) > 0) {
+ $output .= "<tr>\n";
+ $output .= "<td width=\"40%\" class=\"vncellt\">Name</td>\n";
+ $output .= "<td width=\"40%\" class=\"vncellt\">Status</td>\n";
+ $output .= "<td width=\"20%\" class=\"vncellt\">Component</td>\n";
+ $output .= "</tr>\n";
+ foreach ($mirrors as $mirror => $name) {
+ $components = count($name["components"]);
+ $output .= "<tr>\n";
+ $output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['name']}</td>\n";
+ $output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['status']}</td>\n";
+ $output .= "<td width=\"20%\" class=\"listr\">{$name['components'][0]}</td>\n";
+ $output .= "</tr>\n";
+ if (count($name["components"]) > 1) {
+ $morecomponents = array_slice($name["components"], 1);
+ foreach ($morecomponents as $component) {
+ $output .= "<tr>\n";
+ $output .= "<td width=\"20%\" class=\"listr\">{$component}</td>\n";
+ $output .= "</tr>\n";
+ }
+ }
+ }
+ } else {
+ $output .= "<tr><td colspan=\"3\" class=\"listr\">No Mirrors Found</td></tr>\n";
+ }
+ // $output .= "<tr><td colspan=\"3\" class=\"listr\">Updated at " . date("F j, Y, g:i:s a") . "</td></tr>\n";
+ return $output;
+}
+
+/* List all disks in the system (potential gmirror targets) */
+function gmirror_get_disks() {
+ $disklist = "";
+ /* Get a list of disks in a scriptable way, exclude optical drives */
+ exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
+ return $disklist;
+}
+
+/* List all potential gmirror consumers */
+function gmirror_get_unused_consumers() {
+ $consumerlist = "";
+ $disklist = gmirror_get_disks();
+ /* Get a list of consumers, exclude existing mirrors and diskid entries */
+ exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
+ $all_consumers = array();
+ foreach ($consumerlist as $cl) {
+ $parts = explode(" ", $cl);
+ foreach ($parts as $part) {
+ $all_consumers[] = $part;
+ }
+ }
+ foreach ($disklist as $d) {
+ if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
+ $all_consumers[] = $d;
+ }
+ }
+ return $all_consumers;
+}
+
+/* List all existing geom mirrors */
+function gmirror_get_mirrors() {
+ $mirrorlist = "";
+ exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
+ return $mirrorlist;
+}
+
+
+/* List all consumers for a given mirror */
+function gmirror_get_consumers_in_mirror($mirror) {
+ if (!is_valid_mirror($mirror)) {
+ return array();
+ }
+
+ $consumers = array();
+ exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
+ return $consumers;
+}
+
+/* Test if a given consumer is a member of an existing mirror */
+function is_consumer_in_mirror($consumer, $mirror) {
+ if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
+ return false;
+ }
+
+ $mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
+ return in_array(basename($consumer), $mirrorconsumers);
+}
+
+/* Test if a mirror exists */
+function is_valid_mirror($mirror) {
+ $mirrors = gmirror_get_mirrors();
+ return in_array($mirror, $mirrors);
+}
+
+/* Test if a disk is valid/exists */
+function is_valid_disk($disk) {
+ $adisks = gmirror_get_disks();
+ return in_array(basename($disk), $adisks);
+}
+
+/* Test if a consumer is valid and in use in a mirror */
+function is_consumer_used($consumer) {
+ $found = false;
+ $mirrors = gmirror_get_mirrors();
+ foreach ($mirrors as $mirror) {
+ $consumers = gmirror_get_consumers_in_mirror($mirror);
+ if (in_array($consumer, $consumers)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Test if a consumer is valid and not in use */
+function is_consumer_unused($consumer) {
+ $consumers = gmirror_get_unused_consumers();
+ return in_array($consumer, $consumers);
+}
+
+/* Test if a consumer is valid (either a disk or partition) */
+function is_valid_consumer($consumer) {
+ return (is_consumer_unused($consumer) || is_consumer_used($consumer));
+}
+
+/* Remove all disconnected drives from a mirror */
+function gmirror_forget_disconnected($mirror) {
+ if (!is_valid_mirror($mirror)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
+}
+
+/* Insert another consumer into a mirror */
+function gmirror_insert_consumer($mirror, $consumer) {
+ if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
+}
+
+/* Remove consumer from a mirror and clear its metadata */
+function gmirror_remove_consumer($mirror, $consumer) {
+ if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
+}
+
+/* Wipe geom info from drive (if mirror is not running) */
+function gmirror_clear_consumer($consumer) {
+ if (!is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
+}
+
+/* Find the balance method used by a given mirror */
+function gmirror_get_mirror_balance($mirror) {
+ if (!is_valid_mirror($mirror)) {
+ return false;
+ }
+ $balancemethod = "";
+ exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
+ return $balancemethod[0];
+}
+
+/* Change balance algorithm of the mirror */
+function gmirror_configure_balance($mirror, $balancemethod) {
+ global $balance_methods;
+ if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
+}
+
+/* Force a mirror member to rebuild */
+function gmirror_force_rebuild($mirror, $consumer) {
+ if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
+}
+
+/* Show all metadata on the physical consumer */
+function gmirror_get_consumer_metadata($consumer) {
+ if (!is_valid_consumer($consumer)) {
+ return array();
+ }
+ $output = "";
+ exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
+ return array_map('trim', $output);
+}
+
+/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
+function gmirror_consumer_has_metadata($consumer) {
+ return (count(gmirror_get_consumer_metadata($consumer)) > 0);
+}
+
+/* Find the mirror to which this consumer belongs */
+function gmirror_get_consumer_metadata_mirror($consumer) {
+ if (!is_valid_consumer($consumer)) {
+ return array();
+ }
+ $metadata = gmirror_get_consumer_metadata($consumer);
+ foreach ($metadata as $line) {
+ if (substr($line, 0, 5) == "name:") {
+ list ($key, $value) = explode(":", $line, 2);
+ return trim($value);
+ }
+ }
+}
+
+/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
+function gmirror_deactivate_consumer($mirror, $consumer) {
+ if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
+}
+
+/* Reactivate a deactivated consumer */
+function gmirror_activate_consumer($mirror, $consumer) {
+ if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
+ return false;
+ }
+ return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
+}
+
+/* Find the size of the given mirror */
+function gmirror_get_mirror_size($mirror) {
+ if (!is_valid_mirror($mirror)) {
+ return false;
+ }
+ $mirrorsize = "";
+ exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
+ return $mirrorsize[0];
+}
+
+/* Return a list of all potential consumers on a disk with sizes. The geom part
+ list output is a little odd, we can't get the output for just the disk, if the disk contains
+ slices those get output also. */
+function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
+ if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
+ return array();
+ }
+ $output = "";
+ exec("/sbin/geom part list " . escapeshellarg($disk) . " | /usr/bin/egrep '(Name:|Mediasize:)' | /usr/bin/cut -c4- | /usr/bin/sed -l -e 'N;s/\\nMediasize://;P;D;' | /usr/bin/cut -c7-", $output);
+ if (empty($output)) {
+ exec("/sbin/geom disk list " . escapeshellarg($disk) . " | /usr/bin/egrep '(Name:|Mediasize:)' | /usr/bin/cut -c4- | /usr/bin/sed -l -e 'N;s/\\nMediasize://;P;D;' | /usr/bin/cut -c7-", $output);
+ }
+ $disk_contents = array();
+ foreach ($output as $line) {
+ list($name, $size, $humansize) = explode(" ", $line, 3);
+ $consumer = array();
+ $consumer['name'] = $name;
+ $consumer['size'] = $size;
+ $consumer['humansize'] = $humansize;
+ $disk_contents[] = $consumer;
+ }
+ return $disk_contents;
+}
+
+/* Get only the size for one specific potential consumer. */
+function gmirror_get_unused_consumer_size($consumer) {
+ $consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
+ foreach ($consumersizes as $csize) {
+ if ($csize['name'] == $consumer) {
+ return $csize['size'];
+ }
+ }
+ return -1;
+}
+?>
diff --git a/src/etc/inc/growl.class b/src/etc/inc/growl.class
new file mode 100644
index 0000000..8f639e5
--- /dev/null
+++ b/src/etc/inc/growl.class
@@ -0,0 +1,102 @@
+<?PHP
+/*
+ pfSense_MODULE: notifications
+*/
+
+ class Growl
+ {
+ const GROWL_PRIORITY_LOW = -2;
+ const GROWL_PRIORITY_MODERATE = -1;
+ const GROWL_PRIORITY_NORMAL = 0;
+ const GROWL_PRIORITY_HIGH = 1;
+ const GROWL_PRIORITY_EMERGENCY = 2;
+
+ private $appName;
+ private $address;
+ private $notifications;
+ private $password;
+ private $port;
+
+ public function __construct($address, $password = '', $app_name = 'PHP-Growl')
+ {
+ $this->appName = utf8_encode($app_name);
+ $this->address = $address;
+ $this->notifications = array();
+ $this->password = $password;
+ $this->port = 9887;
+ }
+
+ public function addNotification($name, $enabled = true)
+ {
+ $this->notifications[] = array('name' => utf8_encode($name), 'enabled' => $enabled);
+ }
+
+ public function register()
+ {
+ $data = '';
+ $defaults = '';
+ $num_defaults = 0;
+
+ for ($i = 0; $i < count($this->notifications); $i++)
+ {
+ $data .= pack('n', strlen($this->notifications[$i]['name'])) . $this->notifications[$i]['name'];
+ if ($this->notifications[$i]['enabled'])
+ {
+ $defaults .= pack('c', $i);
+ $num_defaults++;
+ }
+ }
+
+ // pack(Protocol version, type, app name, number of notifications to register)
+ $data = pack('c2nc2', 1, 0, strlen($this->appName), count($this->notifications), $num_defaults) . $this->appName . $data . $defaults;
+ $data .= pack('H32', md5($data . $this->password));
+
+ return $this->send($data);
+ }
+
+ public function notify($name, $title, $message, $priority = 0, $sticky = false)
+ {
+ $name = utf8_encode($name);
+ $title = utf8_encode($title);
+ $message = utf8_encode($message);
+ $priority = intval($priority);
+
+ $flags = ($priority & 7) * 2;
+ if ($priority < 0) $flags |= 8;
+ if ($sticky) $flags |= 1;
+
+ // pack(protocol version, type, priority/sticky flags, notification name length, title length, message length. app name length)
+ $data = pack('c2n5', 1, 1, $flags, strlen($name), strlen($title), strlen($message), strlen($this->appName));
+ $data .= $name . $title . $message . $this->appName;
+ $data .= pack('H32', md5($data . $this->password));
+
+ return $this->send($data);
+ }
+
+ private function send($data)
+ {
+ if (function_exists('socket_create') && function_exists('socket_sendto'))
+ {
+ $sck = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ if ($sck) {
+ socket_sendto($sck, $data, strlen($data), 0x100, $this->address, $this->port);
+ return true;
+ }
+ }
+ elseif (function_exists('fsockopen'))
+ {
+ if ($this->address) {
+ $fp = @fsockopen('udp://' . $this->address, $this->port);
+ if ($fp) {
+ fwrite($fp, $data);
+ fclose($fp);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/gwlb.inc b/src/etc/inc/gwlb.inc
new file mode 100644
index 0000000..9880cdc
--- /dev/null
+++ b/src/etc/inc/gwlb.inc
@@ -0,0 +1,1252 @@
+<?php
+/*
+ gwlb.inc
+ Copyright (C) 2008 Bill Marquette, Seth Mos
+ Copyright (C) 2010 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /sbin/route /usr/local/sbin/apinger
+ pfSense_MODULE: routing
+
+ */
+require_once("config.inc");
+require_once("rrd.inc");
+
+/* Returns an array of default values used for apinger.conf */
+function return_apinger_defaults() {
+ return array(
+ "latencylow" => "200",
+ "latencyhigh" => "500",
+ "losslow" => "10",
+ "losshigh" => "20",
+ "interval" => "1",
+ "down" => "10",
+ "avg_delay_samples" => "10",
+ "avg_loss_samples" => "50",
+ "avg_loss_delay_samples" => "20");
+}
+
+/*
+ * Creates monitoring configuration file and
+ * adds appropriate static routes.
+ */
+function setup_gateways_monitor() {
+ global $config, $g;
+
+ $gateways_arr = return_gateways_array();
+ if (!is_array($gateways_arr)) {
+ log_error("No gateways to monitor. Apinger will not be run.");
+ killbypid("{$g['varrun_path']}/apinger.pid");
+ @unlink("{$g['varrun_path']}/apinger.status");
+ return;
+ }
+
+ $apinger_debug = "";
+ if (isset($config['system']['apinger_debug'])) {
+ $apinger_debug = "debug on";
+ }
+
+ $apinger_default = return_apinger_defaults();
+ $apingerconfig = <<<EOD
+
+# pfSense apinger configuration file. Automatically Generated!
+
+{$apinger_debug}
+
+## User and group the pinger should run as
+user "root"
+group "wheel"
+
+## Mailer to use (default: "/usr/lib/sendmail -t")
+#mailer "/var/qmail/bin/qmail-inject"
+
+## Location of the pid-file (default: "/var/run/apinger.pid")
+pid_file "{$g['varrun_path']}/apinger.pid"
+
+## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
+#timestamp_format "%Y%m%d%H%M%S"
+
+status {
+ ## File where the status information should be written to
+ file "{$g['varrun_path']}/apinger.status"
+ ## Interval between file updates
+ ## when 0 or not set, file is written only when SIGUSR1 is received
+ interval 5s
+}
+
+########################################
+# RRDTool status gathering configuration
+# Interval between RRD updates
+rrd interval 60s;
+
+## These parameters can be overridden in a specific alarm configuration
+alarm default {
+ command on "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
+ command off "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
+ combine 10s
+}
+
+## "Down" alarm definition.
+## This alarm will be fired when target doesn't respond for 30 seconds.
+alarm down "down" {
+ time {$apinger_default['down']}s
+}
+
+## "Delay" alarm definition.
+## This alarm will be fired when responses are delayed more than 200ms
+## it will be canceled, when the delay drops below 100ms
+alarm delay "delay" {
+ delay_low {$apinger_default['latencylow']}ms
+ delay_high {$apinger_default['latencyhigh']}ms
+}
+
+## "Loss" alarm definition.
+## This alarm will be fired when packet loss goes over 20%
+## it will be canceled, when the loss drops below 10%
+alarm loss "loss" {
+ percent_low {$apinger_default['losslow']}
+ percent_high {$apinger_default['losshigh']}
+}
+
+target default {
+ ## How often the probe should be sent
+ interval {$apinger_default['interval']}s
+
+ ## How many replies should be used to compute average delay
+ ## for controlling "delay" alarms
+ avg_delay_samples {$apinger_default['avg_delay_samples']}
+
+ ## How many probes should be used to compute average loss
+ avg_loss_samples {$apinger_default['avg_loss_samples']}
+
+ ## The delay (in samples) after which loss is computed
+ ## without this delays larger than interval would be treated as loss
+ avg_loss_delay_samples {$apinger_default['avg_loss_delay_samples']}
+
+ ## Names of the alarms that may be generated for the target
+ alarms "down","delay","loss"
+
+ ## Location of the RRD
+ #rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
+}
+
+EOD;
+
+ $monitor_ips = array();
+ foreach ($gateways_arr as $name => $gateway) {
+ /* Do not monitor if such was requested */
+ if (isset($gateway['monitor_disable'])) {
+ continue;
+ }
+ if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
+ if (is_ipaddr($gateway['gateway'])) {
+ $gateway['monitor'] = $gateway['gateway'];
+ } else { /* No chance to get an ip to monitor skip target. */
+ continue;
+ }
+ }
+
+ /* if the monitor address is already used before, skip */
+ if (in_array($gateway['monitor'], $monitor_ips)) {
+ continue;
+ }
+
+ /* Interface ip is needed since apinger will bind a socket to it.
+ * However the config GUI should already have checked this and when
+ * PPoE is used the IP address is set to "dynamic". So using is_ipaddrv4
+ * or is_ipaddrv6 to identify packet type would be wrong, especially as
+ * further checks (that can cope with the "dynamic" case) are present inside
+ * the if block. So using $gateway['ipprotocol'] is the better option.
+ */
+ if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
+ $gwifip = find_interface_ip($gateway['interface'], true);
+ if (!is_ipaddrv4($gwifip)) {
+ continue; //Skip this target
+ }
+
+ if ($gwifip == "0.0.0.0") {
+ continue; //Skip this target - the gateway is still waiting for DHCP
+ }
+
+ /*
+ * If the gateway is the same as the monitor we do not add a
+ * route as this will break the routing table.
+ * Add static routes for each gateway with their monitor IP
+ * not strictly necessary but is a added level of protection.
+ */
+ if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
+ log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
+ if (interface_isppp_type($gateway['friendlyiface'])) {
+ mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
+ " -iface " . escapeshellarg($gateway['interface']), true);
+ } else {
+ mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
+ " " . escapeshellarg($gateway['gateway']), true);
+ }
+
+ pfSense_kill_states("0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmp");
+ }
+ } else if ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
+ if ($gateway['monitor'] == $gateway['gateway']) {
+ /* link locals really need a different src ip */
+ if (is_linklocal($gateway['gateway'])) {
+ if (!strpos($gateway['gateway'], '%')) {
+ $gateway['gateway'] .= '%' . $gateway['interface'];
+ }
+ $gwifip = find_interface_ipv6_ll($gateway['interface'], true);
+ } else {
+ $gwifip = find_interface_ipv6($gateway['interface'], true);
+ }
+ } else {
+ /* 'monitor' has been set, so makes sure it has precedence over
+ * 'gateway' in defining the source IP. Otherwise if 'gateway'
+ * is a local link and 'monitor' is global routable then the
+ * ICMP6 response would not find its way back home...
+ */
+ $gwifip = find_interface_ipv6($gateway['interface'], true);
+ }
+
+ /* Make sure srcip and target have scope defined when they are ll */
+ if (is_linklocal($gwifip) && !strpos($gwifip, '%')) {
+ $gwifip .= '%' . $gateway['interface'];
+ }
+ if (is_linklocal($gateway['monitor']) && !strpos($gateway['monitor'], '%')) {
+ $gateway['monitor'] .= "%{$gateway['interface']}";
+ }
+
+ if (!is_ipaddrv6($gwifip)) {
+ continue; //Skip this target
+ }
+
+ /*
+ * If the gateway is the same as the monitor we do not add a
+ * route as this will break the routing table.
+ * Add static routes for each gateway with their monitor IP
+ * not strictly necessary but is a added level of protection.
+ */
+ if ($gateway['gateway'] != $gateway['monitor']) {
+ log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
+ if (interface_isppp_type($gateway['friendlyiface'])) {
+ mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
+ " -iface " . escapeshellarg($gateway['interface']), true);
+ } else {
+ mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
+ " " . escapeshellarg($gateway['gateway']), true);
+ }
+
+ pfSense_kill_states("::0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmpv6");
+ }
+ } else {
+ continue;
+ }
+
+ $monitor_ips[] = $gateway['monitor'];
+ $apingercfg = "target \"{$gateway['monitor']}\" {\n";
+ $apingercfg .= " description \"{$name}\"\n";
+ $apingercfg .= " srcip \"{$gwifip}\"\n";
+
+ ## How often the probe should be sent
+ if (!empty($gateway['interval']) && is_numeric($gateway['interval'])) {
+ $interval = intval($gateway['interval']); # Restrict to Integer
+ if ($interval < 1) {
+ $interval = 1; # Minimum
+ }
+ if ($interval != $apinger_default['interval']) { # If not default value
+ $apingercfg .= " interval " . $interval . "s\n";
+ }
+ }
+
+ ## How many replies should be used to compute average delay
+ ## for controlling "delay" alarms
+ if (!empty($gateway['avg_delay_samples']) && is_numeric($gateway['avg_delay_samples'])) {
+ $avg_delay_samples = intval($gateway['avg_delay_samples']); # Restrict to Integer
+ if ($avg_delay_samples < 1) {
+ $avg_delay_samples = 1; # Minimum
+ }
+ if ($avg_delay_samples != $apinger_default['avg_delay_samples']) { # If not default value
+ $apingercfg .= " avg_delay_samples " . $avg_delay_samples . "\n";
+ }
+ }
+
+ ## How many probes should be used to compute average loss
+ if (!empty($gateway['avg_loss_samples']) && is_numeric($gateway['avg_loss_samples'])) {
+ $avg_loss_samples = intval($gateway['avg_loss_samples']); # Restrict to Integer
+ if ($avg_loss_samples < 1) {
+ $avg_loss_samples = 1; # Minimum
+ }
+ if ($avg_loss_samples != $apinger_default['avg_loss_samples']) { # If not default value
+ $apingercfg .= " avg_loss_samples " . $avg_loss_samples . "\n";
+ }
+ }
+
+ ## The delay (in samples) after which loss is computed
+ ## without this delays larger than interval would be treated as loss
+ if (!empty($gateway['avg_loss_delay_samples']) && is_numeric($gateway['avg_loss_delay_samples'])) {
+ $avg_loss_delay_samples = intval($gateway['avg_loss_delay_samples']); # Restrict to Integer
+ if ($avg_loss_delay_samples < 1) {
+ $avg_loss_delay_samples = 1; # Minimum
+ }
+ if ($avg_loss_delay_samples != $apinger_default['avg_loss_delay_samples']) { # If not default value
+ $apingercfg .= " avg_loss_delay_samples " . $avg_loss_delay_samples . "\n";
+ }
+ }
+
+ $alarms = "";
+ $alarmscfg = "";
+ $override = false;
+ if (!empty($gateway['losslow'])) {
+ $alarmscfg .= "alarm loss \"{$name}loss\" {\n";
+ $alarmscfg .= "\tpercent_low {$gateway['losslow']}\n";
+ $alarmscfg .= "\tpercent_high {$gateway['losshigh']}\n";
+ $alarmscfg .= "}\n";
+ $alarms .= "\"{$name}loss\"";
+ $override = true;
+ } else {
+ if ($override == true) {
+ $alarms .= ",";
+ }
+ $alarms .= "\"loss\"";
+ $override = true;
+ }
+ if (!empty($gateway['latencylow'])) {
+ $alarmscfg .= "alarm delay \"{$name}delay\" {\n";
+ $alarmscfg .= "\tdelay_low {$gateway['latencylow']}ms\n";
+ $alarmscfg .= "\tdelay_high {$gateway['latencyhigh']}ms\n";
+ $alarmscfg .= "}\n";
+ if ($override == true) {
+ $alarms .= ",";
+ }
+ $alarms .= "\"{$name}delay\"";
+ $override = true;
+ } else {
+ if ($override == true) {
+ $alarms .= ",";
+ }
+ $alarms .= "\"delay\"";
+ $override = true;
+ }
+ if (!empty($gateway['down'])) {
+ $alarmscfg .= "alarm down \"{$name}down\" {\n";
+ $alarmscfg .= "\ttime {$gateway['down']}s\n";
+ $alarmscfg .= "}\n";
+ if ($override == true) {
+ $alarms .= ",";
+ }
+ $alarms .= "\"{$name}down\"";
+ $override = true;
+ } else {
+ if ($override == true) {
+ $alarms .= ",";
+ }
+ $alarms .= "\"down\"";
+ $override = true;
+ }
+ if ($override == true) {
+ $apingercfg .= "\talarms override {$alarms};\n";
+ }
+
+ if (isset($gateway['force_down'])) {
+ $apingercfg .= "\tforce_down on\n";
+ }
+
+ $apingercfg .= " rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
+ $apingercfg .= "}\n";
+ $apingercfg .= "\n";
+
+ $apingerconfig .= $alarmscfg;
+ $apingerconfig .= $apingercfg;
+
+ # Create gateway quality RRD with settings more suitable for pfSense graph set,
+ # since apinger uses default step (300; 5 minutes) and other settings that don't
+ # match the pfSense gateway quality graph set.
+ create_gateway_quality_rrd("{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd");
+ }
+ @file_put_contents("{$g['varetc_path']}/apinger.conf", $apingerconfig);
+ unset($apingerconfig);
+
+ /* Restart apinger process */
+ if (isvalidpid("{$g['varrun_path']}/apinger.pid")) {
+ sigkillbypid("{$g['varrun_path']}/apinger.pid", "HUP");
+ } else {
+ /* start a new apinger process */
+ @unlink("{$g['varrun_path']}/apinger.status");
+ sleep(1);
+ mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
+ sleep(1);
+ sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
+ }
+
+ return 0;
+}
+
+/* return the status of the apinger targets as a array */
+function return_gateways_status($byname = false) {
+ global $config, $g;
+
+ $apingerstatus = array();
+ /* Always get the latest status from apinger */
+ if (file_exists("{$g['varrun_path']}/apinger.pid")) {
+ sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
+ }
+ if (file_exists("{$g['varrun_path']}/apinger.status")) {
+ $apingerstatus = file("{$g['varrun_path']}/apinger.status");
+ } else {
+ $apingerstatus = array();
+ }
+
+ $status = array();
+ foreach ($apingerstatus as $line) {
+ $info = explode("|", $line);
+ if ($byname == false) {
+ $target = $info[0];
+ } else {
+ $target = $info[2];
+ }
+
+ $status[$target] = array();
+ $status[$target]['monitorip'] = $info[0];
+ $status[$target]['srcip'] = $info[1];
+ $status[$target]['name'] = $info[2];
+ $status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
+ $status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
+ $status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
+ $status[$target]['status'] = trim($info[8]);
+ }
+
+ /* tack on any gateways that have monitoring disabled
+ * or are down, which could cause gateway groups to fail */
+ $gateways_arr = return_gateways_array();
+ foreach ($gateways_arr as $gwitem) {
+ if (!isset($gwitem['monitor_disable'])) {
+ continue;
+ }
+ if (!is_ipaddr($gwitem['monitorip'])) {
+ $realif = $gwitem['interface'];
+ $tgtip = get_interface_gateway($realif);
+ if (!is_ipaddr($tgtip)) {
+ $tgtip = "none";
+ }
+ $srcip = find_interface_ip($realif);
+ } else {
+ $tgtip = $gwitem['monitorip'];
+ $srcip = find_interface_ip($realif);
+ }
+ if ($byname == true) {
+ $target = $gwitem['name'];
+ } else {
+ $target = $tgtip;
+ }
+
+ /* failsafe for down interfaces */
+ if ($target == "none") {
+ $target = $gwitem['name'];
+ $status[$target]['name'] = $gwitem['name'];
+ $status[$target]['lastcheck'] = date('r');
+ $status[$target]['delay'] = "0.0ms";
+ $status[$target]['loss'] = "100.0%";
+ $status[$target]['status'] = "down";
+ } else {
+ $status[$target]['monitorip'] = $tgtip;
+ $status[$target]['srcip'] = $srcip;
+ $status[$target]['name'] = $gwitem['name'];
+ $status[$target]['lastcheck'] = date('r');
+ $status[$target]['delay'] = "0.0ms";
+ $status[$target]['loss'] = "0.0%";
+ $status[$target]['status'] = "none";
+ }
+ }
+ return($status);
+}
+
+/* Return all configured gateways on the system */
+function return_gateways_array($disabled = false, $localhost = false, $inactive = false) {
+ global $config, $g;
+
+ $gateways_arr = array();
+ $gateways_arr_temp = array();
+
+ $found_defaultv4 = 0;
+ $found_defaultv6 = 0;
+
+ // Ensure the interface cache is up to date first
+ $interfaces = get_interface_arr(true);
+ $interfaces_v4 = array();
+ $interfaces_v6 = array();
+
+ $i = -1;
+ /* Process/add all the configured gateways. */
+ if (is_array($config['gateways']['gateway_item'])) {
+ foreach ($config['gateways']['gateway_item'] as $gateway) {
+ /* Increment it here to do not skip items */
+ $i++;
+
+ if (empty($config['interfaces'][$gateway['interface']])) {
+ if ($inactive === false) {
+ continue;
+ } else {
+ $gateway['inactive'] = true;
+ }
+ }
+ $wancfg = $config['interfaces'][$gateway['interface']];
+
+ /* skip disabled interfaces */
+ if ($disabled === false && (!isset($wancfg['enable']))) {
+ continue;
+ }
+
+ /* if the gateway is dynamic and we can find the IPv4, Great! */
+ if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic") {
+ if ($gateway['ipprotocol'] == "inet") {
+ /* we know which interfaces is dynamic, this should be made a function */
+ $gateway['gateway'] = get_interface_gateway($gateway['interface']);
+ /* no IP address found, set to dynamic */
+ if (!is_ipaddrv4($gateway['gateway'])) {
+ $gateway['gateway'] = "dynamic";
+ }
+ $gateway['dynamic'] = true;
+ }
+
+ /* if the gateway is dynamic and we can find the IPv6, Great! */
+ else if ($gateway['ipprotocol'] == "inet6") {
+ /* we know which interfaces is dynamic, this should be made a function, and for v6 too */
+ $gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
+ /* no IPv6 address found, set to dynamic */
+ if (!is_ipaddrv6($gateway['gateway'])) {
+ $gateway['gateway'] = "dynamic";
+ }
+ $gateway['dynamic'] = true;
+ }
+ } else {
+ /* getting this detection right is hard at this point because we still don't
+ * store the address family in the gateway item */
+ if (is_ipaddrv4($gateway['gateway'])) {
+ $gateway['ipprotocol'] = "inet";
+ } else if (is_ipaddrv6($gateway['gateway'])) {
+ $gateway['ipprotocol'] = "inet6";
+ }
+ }
+
+ if (isset($gateway['monitor_disable'])) {
+ $gateway['monitor_disable'] = true;
+ } else if (empty($gateway['monitor'])) {
+ $gateway['monitor'] = $gateway['gateway'];
+ }
+
+ $gateway['friendlyiface'] = $gateway['interface'];
+
+ /* special treatment for tunnel interfaces */
+ if ($gateway['ipprotocol'] == "inet6") {
+ $gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
+ $interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
+ } else {
+ $gateway['interface'] = get_real_interface($gateway['interface'], "all", false, false);
+ $interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
+ }
+
+ /* entry has a default flag, use it */
+ if (isset($gateway['defaultgw'])) {
+ if ($gateway['ipprotocol'] == "inet") {
+ $gateway['defaultgw'] = true;
+ $found_defaultv4 = 1;
+ } else if ($gateway['ipprotocol'] == "inet6") {
+ $gateway['defaultgw'] = true;
+ $found_defaultv6 = 1;
+ }
+ }
+ /* include the gateway index as the attribute */
+ $gateway['attribute'] = $i;
+
+ /* Remember all the gateway names, even ones to be skipped because they are disabled. */
+ /* Then we can easily know and match them later when attempting to add dynamic gateways to the list. */
+ $gateways_arr_temp[$gateway['name']] = $gateway;
+
+ /* skip disabled gateways if the caller has not asked for them to be returned. */
+ if (!($disabled === false && isset($gateway['disabled']))) {
+ $gateways_arr[$gateway['name']] = $gateway;
+ }
+ }
+ }
+ unset($gateway);
+
+ /* Loop through all interfaces with a gateway and add it to a array */
+ if ($disabled == false) {
+ $iflist = get_configured_interface_with_descr();
+ } else {
+ $iflist = get_configured_interface_with_descr(false, true);
+ }
+
+ /* Process/add dynamic v4 gateways. */
+ foreach ($iflist as $ifname => $friendly) {
+ if (!interface_has_gateway($ifname)) {
+ continue;
+ }
+
+ if (empty($config['interfaces'][$ifname])) {
+ continue;
+ }
+
+ $ifcfg = &$config['interfaces'][$ifname];
+ if (!isset($ifcfg['enable'])) {
+ continue;
+ }
+
+ if (!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr'])) {
+ continue;
+ }
+
+ if (isset($interfaces_v4[$ifname])) {
+ continue;
+ }
+
+ $ctype = "";
+ switch ($ifcfg['ipaddr']) {
+ case "dhcp":
+ case "pppoe":
+ case "pptp":
+ case "ppp":
+ $ctype = strtoupper($ifcfg['ipaddr']);
+ break;
+ default:
+ $tunnelif = substr($ifcfg['if'], 0, 3);
+ if (substr($ifcfg['if'], 0, 4) == "ovpn") {
+ // if current iface is an ovpn server endpoint then check its type, skip tap only
+ if (substr($ifcfg['if'], 4, 1) == 's') {
+ $ovpnid = substr($ifcfg['if'], 5);
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $ovpnserverconf) {
+ if ($ovpnserverconf['vpnid'] == $ovpnid) {
+ if ($ovpnserverconf['dev_mode'] == "tap") {
+ continue 3;
+ }
+ }
+ }
+ }
+ }
+ $ctype = "VPNv4";
+ } else if ($tunnelif == "gif" || $tunnelif == "gre") {
+ $ctype = "TUNNELv4";
+ }
+ break;
+ }
+ $ctype = "_". strtoupper($ctype);
+
+ $gateway = array();
+ $gateway['dynamic'] = false;
+ $gateway['ipprotocol'] = "inet";
+ $gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
+ $gateway['interface'] = get_real_interface($ifname);
+ $gateway['friendlyiface'] = $ifname;
+ $gateway['name'] = "{$friendly}{$ctype}";
+ $gateway['attribute'] = "system";
+
+ if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
+ $gateway['defaultgw'] = true;
+ $gateway['dynamic'] = true;
+ $found_defaultv4 = 1;
+ }
+ /* Loopback dummy for dynamic interfaces without a IP */
+ if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true) {
+ $gateway['gateway'] = "dynamic";
+ }
+
+ /* automatically skip known static and dynamic gateways that were previously processed */
+ foreach ($gateways_arr_temp as $gateway_item) {
+ if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
+ (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
+ continue 2;
+ }
+ }
+
+ if (is_ipaddrv4($gateway['gateway'])) {
+ $gateway['monitor'] = $gateway['gateway'];
+ }
+
+ $gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
+ $gateways_arr[$gateway['name']] = $gateway;
+ }
+ unset($gateway);
+
+ /* Process/add dynamic v6 gateways. */
+ foreach ($iflist as $ifname => $friendly) {
+ /* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
+ if (!isset($config['system']['ipv6allow'])) {
+ break;
+ }
+
+ if (!interface_has_gatewayv6($ifname)) {
+ continue;
+ }
+
+ if (empty($config['interfaces'][$ifname])) {
+ continue;
+ }
+
+ $ifcfg = &$config['interfaces'][$ifname];
+ if (!isset($ifcfg['enable'])) {
+ continue;
+ }
+
+ if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
+ continue;
+ }
+
+ if (isset($interfaces_v6[$ifname])) {
+ continue;
+ }
+
+ $ctype = "";
+ switch ($ifcfg['ipaddrv6']) {
+ case "slaac":
+ case "dhcp6":
+ case "6to4":
+ case "6rd":
+ $ctype = strtoupper($ifcfg['ipaddrv6']);
+ break;
+ default:
+ $tunnelif = substr($ifcfg['if'], 0, 3);
+ if (substr($ifcfg['if'], 0, 4) == "ovpn") {
+ // if current iface is an ovpn server endpoint then check its type, skip tap only
+ if (substr($ifcfg['if'], 4, 1) == 's') {
+ $ovpnid = substr($ifcfg['if'], 5);
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $ovpnserverconf) {
+ if ($ovpnserverconf['vpnid'] == $ovpnid) {
+ if ($ovpnserverconf['dev_mode'] == "tap") {
+ continue 3;
+ }
+ }
+ }
+ }
+ }
+ $ctype = "VPNv6";
+ } else if ($tunnelif == "gif" || $tunnelif == "gre") {
+ $ctype = "TUNNELv6";
+ }
+ break;
+ }
+ $ctype = "_". strtoupper($ctype);
+
+ $gateway = array();
+ $gateway['dynamic'] = false;
+ $gateway['ipprotocol'] = "inet6";
+ $gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
+ $gateway['interface'] = get_real_interface($ifname, "inet6");
+ switch ($ifcfg['ipaddrv6']) {
+ case "6rd":
+ case "6to4":
+ $gateway['dynamic'] = "default";
+ break;
+ }
+ $gateway['friendlyiface'] = $ifname;
+ $gateway['name'] = "{$friendly}{$ctype}";
+ $gateway['attribute'] = "system";
+
+ if (($gateway['dynamic'] === "default") && ($found_defaultv6 == 0)) {
+ $gateway['defaultgw'] = true;
+ $gateway['dynamic'] = true;
+ $found_defaultv6 = 1;
+ }
+
+ /* Loopback dummy for dynamic interfaces without a IP */
+ if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true) {
+ $gateway['gateway'] = "dynamic";
+ }
+
+ /* automatically skip known static and dynamic gateways that were previously processed */
+ foreach ($gateways_arr_temp as $gateway_item) {
+ if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
+ (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
+ continue 2;
+ }
+ }
+
+ if (is_ipaddrv6($gateway['gateway'])) {
+ $gateway['monitor'] = $gateway['gateway'];
+ }
+
+ $gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
+ $gateways_arr[$gateway['name']] = $gateway;
+ }
+ unset($gateway);
+
+ /* FIXME: Should this be enabled.
+ * Some interface like wan might be default but have no info recorded
+ * the config. */
+ /* this is a fallback if all else fails and we want to get packets out @smos */
+ if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
+ foreach ($gateways_arr as &$gateway) {
+ if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
+ if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
+ $gateway['defaultgw'] = true;
+ $found_defaultv4 = 1;
+ }
+ }
+ else if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
+ if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
+ $gateway['defaultgw'] = true;
+ $found_defaultv6 = 1;
+ }
+ }
+ }
+ }
+
+ if ($localhost === true) {
+ /* attach localhost for Null routes */
+ $gwlo4 = array();
+ $gwlo4['name'] = "Null4";
+ $gwlo4['interface'] = "lo0";
+ $gwlo4['ipprotocol'] = "inet";
+ $gwlo4['gateway'] = "127.0.0.1";
+ $gwlo6 = array();
+ $gwlo6['name'] = "Null6";
+ $gwlo6['interface'] = "lo0";
+ $gwlo6['ipprotocol'] = "inet6";
+ $gwlo6['gateway'] = "::1";
+ $gateways_arr['Null4'] = $gwlo4;
+ $gateways_arr['Null6'] = $gwlo6;
+ }
+ return($gateways_arr);
+}
+
+function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
+ global $config, $g;
+ /*
+ * NOTE: The code below is meant to replace the default gateway when it goes down.
+ * This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
+ */
+ $upgw = '';
+ $dfltgwname = '';
+ $dfltgwdown = false;
+ $dfltgwfound = false;
+ foreach ($gateways_arr as $gwname => $gwsttng) {
+ if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
+ $dfltgwfound = true;
+ $dfltgwname = $gwname;
+ if (!isset($gwsttng['monitor_disable']) && $gateways_status[$gwname]['status'] != "none") {
+ $dfltgwdown = true;
+ }
+ }
+ /* Keep a record of the last up gateway */
+ /* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
+ if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || $gateways_status[$gwname]['status'] == "none") && $gwsttng[$gwname]['friendlyiface'] != "lan") {
+ $upgw = $gwname;
+ }
+ if ($dfltgwdown == true && !empty($upgw)) {
+ break;
+ }
+ }
+ if ($dfltgwfound == false) {
+ $gwname = convert_friendly_interface_to_friendly_descr("wan");
+ if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down")) {
+ $dfltgwdown = true;
+ }
+ }
+ if ($dfltgwdown == true && !empty($upgw)) {
+ if ($gateways_arr[$upgw]['gateway'] == "dynamic") {
+ $gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
+ }
+ if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
+ log_error("Default gateway down setting {$upgw} as default!");
+ if (is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
+ $inetfamily = "-inet6";
+ } else {
+ $inetfamily = "-inet";
+ }
+ mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
+ }
+ } else if (!empty($dfltgwname)) {
+ $defaultgw = trim(exec("/sbin/route -n get -{$ipprotocol} default | /usr/bin/awk '/gateway:/ {print $2}'"), " \n");
+ if ($ipprotocol == 'inet6' && !is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
+ return;
+ }
+ if ($ipprotocol == 'inet' && !is_ipaddrv4($gateways_arr[$dfltgwname]['gateway'])) {
+ return;
+ }
+ if ($defaultgw != $gateways_arr[$dfltgwname]['gateway']) {
+ mwexec("/sbin/route change -{$ipprotocol} default {$gateways_arr[$dfltgwname]['gateway']}");
+ }
+ }
+}
+
+/*
+ * Return an array with all gateway groups with name as key
+ * All gateway groups will be processed before returning the array.
+ */
+function return_gateway_groups_array() {
+ global $config, $g;
+
+ /* fetch the current gateways status */
+ $gateways_status = return_gateways_status(true);
+ $gateways_arr = return_gateways_array();
+ $gateway_groups_array = array();
+
+ if (isset($config['system']['gw_switch_default'])) {
+ fixup_default_gateway("inet", $gateways_status, $gateways_arr);
+ fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
+ }
+ if (is_array($config['gateways']['gateway_group'])) {
+ $carplist = get_configured_carp_interface_list();
+ foreach ($config['gateways']['gateway_group'] as $group) {
+ /* create array with group gateways members separated by tier */
+ $tiers = array();
+ $backupplan = array();
+ $gwvip_arr = array();
+ foreach ($group['item'] as $item) {
+ list($gwname, $tier, $vipname) = explode("|", $item);
+
+ if (is_ipaddr($carplist[$vipname])) {
+ if (!is_array($gwvip_arr[$group['name']])) {
+ $gwvip_arr[$group['name']] = array();
+ }
+ $gwvip_arr[$group['name']][$gwname] = $vipname;
+ }
+
+ /* Do it here rather than reiterating again the group in case no member is up. */
+ if (!is_array($backupplan[$tier])) {
+ $backupplan[$tier] = array();
+ }
+ $backupplan[$tier][] = $gwname;
+
+ /* check if the gateway is available before adding it to the array */
+ if (is_array($gateways_status[$gwname])) {
+ $status = $gateways_status[$gwname];
+ $gwdown = false;
+ if (stristr($status['status'], "down")) {
+ $msg = sprintf(gettext("MONITOR: %s is down, omitting from routing group {$group['name']}"), $gwname);
+ $gwdown = true;
+ } else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
+ /* packet loss */
+ $msg = sprintf(gettext("MONITOR: %s has packet loss, omitting from routing group {$group['name']}"), $gwname);
+ $gwdown = true;
+ } else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
+ /* high latency */
+ $msg = sprintf(gettext("MONITOR: %s has high latency, omitting from routing group {$group['name']}"), $gwname);
+ $gwdown = true;
+ }
+ if ($gwdown == true) {
+ log_error($msg);
+ notify_via_growl($msg);
+ notify_via_smtp($msg);
+ } else {
+ /* Online add member */
+ if (!is_array($tiers[$tier])) {
+ $tiers[$tier] = array();
+ }
+ $tiers[$tier][] = $gwname;
+ }
+ } else if (isset($gateways_arr[$gwname]['monitor_disable'])) {
+ $tiers[$tier][] = $gwname;
+ }
+ }
+ $tiers_count = count($tiers);
+ if ($tiers_count == 0) {
+ /* Oh dear, we have no members! Engage Plan B */
+ if (!platform_booting()) {
+ $msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
+ log_error($msg);
+ notify_via_growl($msg);
+ //notify_via_smtp($msg);
+ }
+ $tiers = $backupplan;
+ }
+ /* sort the tiers array by the tier key */
+ ksort($tiers);
+
+ /* we do not really foreach the tiers as we stop after the first tier */
+ foreach ($tiers as $tieridx => $tier) {
+ /* process all gateways in this tier */
+ foreach ($tier as $member) {
+ /* determine interface gateway */
+ if (isset($gateways_arr[$member])) {
+ $gateway = $gateways_arr[$member];
+ $int = $gateway['interface'];
+ $gatewayip = "";
+ if (is_ipaddr($gateway['gateway'])) {
+ $gatewayip = $gateway['gateway'];
+ } else if (!empty($int)) {
+ $gatewayip = get_interface_gateway($gateway['friendlyiface']);
+ }
+
+ if (!empty($int)) {
+ $gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
+ if (is_ipaddr($gatewayip)) {
+ $groupmember = array();
+ $groupmember['int'] = $int;
+ $groupmember['gwip'] = $gatewayip;
+ $groupmember['weight'] = isset($gateway['weight']) ? $gateway['weight'] : 1;
+ if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$member])) {
+ $groupmember['vip'] = $gwvip_arr[$group['name']][$member];
+ }
+ $gateway_groups_array[$group['name']][] = $groupmember;
+ }
+ }
+ }
+ }
+ /* we should have the 1st available tier now, exit stage left */
+ if (count($gateway_groups_array[$group['name']]) > 0) {
+ break;
+ } else {
+ log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
+ }
+ }
+ }
+ }
+
+ return ($gateway_groups_array);
+}
+
+/* Update DHCP WAN Interface ip address in gateway group item */
+function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
+ global $config, $g;
+ foreach ($config['gateways']['gateway_item'] as & $gw) {
+ if ($gw['interface'] == $interface) {
+ $current_gw = get_interface_gateway($interface);
+ if ($gw['gateway'] <> $current_gw) {
+ $gw['gateway'] = $current_gw;
+ $changed = true;
+ }
+ }
+ }
+ if ($changed && $current_gw) {
+ write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
+ }
+}
+
+function lookup_gateway_ip_by_name($name, $disabled = false) {
+
+ $gateways_arr = return_gateways_array($disabled, true);
+ foreach ($gateways_arr as $gname => $gw) {
+ if ($gw['name'] === $name || $gname === $name) {
+ return $gw['gateway'];
+ }
+ }
+
+ return false;
+}
+
+function lookup_gateway_monitor_ip_by_name($name) {
+
+ $gateways_arr = return_gateways_array(false, true);
+ if (!empty($gateways_arr[$name])) {
+ $gateway = $gateways_arr[$name];
+ if (!is_ipaddr($gateway['monitor'])) {
+ return $gateway['gateway'];
+ }
+
+ return $gateway['monitor'];
+ }
+
+ return (false);
+}
+
+function lookup_gateway_interface_by_name($name) {
+
+ $gateways_arr = return_gateways_array(false, true);
+ if (!empty($gateways_arr[$name])) {
+ $interfacegw = $gateways_arr[$name]['friendlyiface'];
+ return ($interfacegw);
+ }
+
+ return (false);
+}
+
+function get_interface_gateway($interface, &$dynamic = false) {
+ global $config, $g;
+
+ if (substr($interface, 0, 4) == '_vip') {
+ $interface = get_configured_carp_interface_list($interface, 'inet', 'iface');
+ }
+
+ $gw = NULL;
+ $gwcfg = $config['interfaces'][$interface];
+ if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
+ foreach ($config['gateways']['gateway_item'] as $gateway) {
+ if (($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
+ $gw = $gateway['gateway'];
+ break;
+ }
+ }
+ }
+
+ // for dynamic interfaces we handle them through the $interface_router file.
+ if (($gw == NULL || !is_ipaddrv4($gw)) && !is_ipaddrv4($gwcfg['ipaddr'])) {
+ $realif = get_real_interface($interface);
+ if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
+ $gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
+ $dynamic = true;
+ }
+ if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw")) {
+ $dynamic = "default";
+ }
+
+ }
+
+ /* return gateway */
+ return ($gw);
+}
+
+function get_interface_gateway_v6($interface, &$dynamic = false) {
+ global $config, $g;
+
+ if (substr($interface, 0, 4) == '_vip') {
+ $interface = get_configured_carp_interface_list($interface, 'inet6', 'iface');
+ }
+
+ $gw = NULL;
+ $gwcfg = $config['interfaces'][$interface];
+ if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
+ foreach ($config['gateways']['gateway_item'] as $gateway) {
+ if (($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
+ $gw = $gateway['gateway'];
+ break;
+ }
+ }
+ }
+
+ // for dynamic interfaces we handle them through the $interface_router file.
+ if (($gw == NULL || !is_ipaddrv6($gw)) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
+ $realif = get_real_interface($interface);
+ if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
+ $gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
+ $dynamic = true;
+ }
+ if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6")) {
+ $dynamic = "default";
+ }
+ }
+ /* return gateway */
+ return ($gw);
+}
+
+/* Check a IP address against a gateway IP or name
+ * to verify it's address family */
+function validate_address_family($ipaddr, $gwname, $disabled = false) {
+ $v4ip = false;
+ $v6ip = false;
+ $v4gw = false;
+ $v6gw = false;
+
+ if (is_ipaddrv4($ipaddr)) {
+ $v4ip = true;
+ }
+ if (is_ipaddrv6($ipaddr)) {
+ $v6ip = true;
+ }
+ if (is_ipaddrv4($gwname)) {
+ $v4gw = true;
+ }
+ if (is_ipaddrv6($gwname)) {
+ $v6gw = true;
+ }
+
+ if ($v4ip && $v4gw) {
+ return true;
+ }
+ if ($v6ip && $v6gw) {
+ return true;
+ }
+
+ /* still no match, carry on, lookup gateways */
+ if (is_ipaddrv4(lookup_gateway_ip_by_name($gwname, $disabled))) {
+ $v4gw = true;
+ }
+ if (is_ipaddrv6(lookup_gateway_ip_by_name($gwname, $disabled))) {
+ $v6gw = true;
+ }
+
+ $gw_array = return_gateways_array();
+ if (is_array($gw_array[$gwname])) {
+ switch ($gw_array[$gwname]['ipprotocol']) {
+ case "inet":
+ $v4gw = true;
+ break;
+ case "inet6":
+ $v6gw = true;
+ break;
+ }
+ }
+
+ if ($v4ip && $v4gw) {
+ return true;
+ }
+ if ($v6ip && $v6gw) {
+ return true;
+ }
+
+ return false;
+}
+
+/* check if a interface is part of a gateway group */
+function interface_gateway_group_member($interface) {
+ global $config;
+
+ if (is_array($config['gateways']['gateway_group'])) {
+ $groups = $config['gateways']['gateway_group'];
+ } else {
+ return false;
+ }
+
+ $gateways_arr = return_gateways_array(false, true);
+ foreach ($groups as $group) {
+ if (is_array($group['item'])) {
+ foreach ($group['item'] as $item) {
+ $elements = explode("|", $item);
+ $gwname = $elements[0];
+ if ($interface == $gateways_arr[$gwname]['interface']) {
+ unset($gateways_arr);
+ return true;
+ }
+ }
+ }
+ }
+ unset($gateways_arr);
+
+ return false;
+}
+
+function gateway_is_gwgroup_member($name) {
+ global $config;
+
+ if (is_array($config['gateways']['gateway_group'])) {
+ $groups = $config['gateways']['gateway_group'];
+ } else {
+ return false;
+ }
+
+ $members = array();
+ foreach ($groups as $group) {
+ if (is_array($group['item'])) {
+ foreach ($group['item'] as $item) {
+ $elements = explode("|", $item);
+ $gwname = $elements[0];
+ if ($name == $elements[0]) {
+ $members[] = $group['name'];
+ }
+ }
+ }
+ }
+
+ return $members;
+}
+?> \ No newline at end of file
diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc
new file mode 100644
index 0000000..4d9389a
--- /dev/null
+++ b/src/etc/inc/interfaces.inc
@@ -0,0 +1,5814 @@
+<?php
+/*
+ interfaces.inc
+ Copyright (C) 2004-2008 Scott Ullrich
+ Copyright (C) 2008-2009 Ermal Luçi
+ All rights reserved.
+
+ function interfaces_wireless_configure is
+ Copyright (C) 2005 Espen Johansen
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notices,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notices, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /sbin/dhclient /bin/sh /usr/bin/grep /usr/bin/xargs /usr/bin/awk /usr/local/sbin/choparp
+ pfSense_BUILDER_BINARIES: /sbin/ifconfig /sbin/route /usr/sbin/ngctl /usr/sbin/arp /bin/kill /usr/local/sbin/mpd5
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/dhcp6c
+ pfSense_MODULE: interfaces
+
+*/
+
+/* include all configuration functions */
+require_once("globals.inc");
+require_once("util.inc");
+require_once("gwlb.inc");
+
+function interfaces_bring_up($interface) {
+ if (!$interface) {
+ log_error(gettext("interfaces_bring_up() was called but no variable defined."));
+ log_error("Backtrace: " . debug_backtrace());
+ return;
+ }
+ pfSense_interface_flags($interface, IFF_UP);
+}
+
+/*
+ * Return the interface array
+ */
+function get_interface_arr($flush = false) {
+ global $interface_arr_cache;
+
+ /* If the cache doesn't exist, build it */
+ if (!isset($interface_arr_cache) or $flush) {
+ $interface_arr_cache = pfSense_interface_listget();
+ }
+
+ return $interface_arr_cache;
+}
+
+/*
+ * does_interface_exist($interface): return true or false if a interface is
+ * detected.
+ */
+function does_interface_exist($interface, $flush = true) {
+ global $config;
+
+ if (!$interface) {
+ return false;
+ }
+
+ $ints = get_interface_arr($flush);
+ if (in_array($interface, $ints)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*
+ * does_vip_exist($vip): return true or false if a vip is
+ * configured.
+ */
+function does_vip_exist($vip) {
+ global $config;
+
+ if (!$vip) {
+ return false;
+ }
+
+
+ switch ($vip['mode']) {
+ case "carp":
+ case "ipalias":
+ /* XXX: Make proper checks? */
+ $realif = get_real_interface($vip['interface']);
+ if (!does_interface_exist($realif)) {
+ return false;
+ }
+ break;
+ case "proxyarp":
+ /* XXX: Implement this */
+ default:
+ return false;
+ }
+
+ $ifacedata = pfSense_getall_interface_addresses($realif);
+ foreach ($ifacedata as $vipips) {
+ if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function interface_netgraph_needed($interface = "wan") {
+ global $config;
+
+ $found = false;
+ if (!empty($config['pptpd']) &&
+ $config['pptpd']['mode'] == "server") {
+ $found = true;
+ }
+ if ($found == false && !empty($config['l2tp']) &&
+ $config['l2tp']['mode'] == "server") {
+ $found = true;
+ }
+ if ($found == false && is_array($config['pppoes']['pppoe'])) {
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ if ($pppoe['mode'] != "server") {
+ continue;
+ }
+ if ($pppoe['interface'] == $interface) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ if ($found == false) {
+ $found = interface_isppp_type($interface);
+ }
+
+ if ($found == false) {
+ $realif = get_real_interface($interface);
+ if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
+ $ports = explode(',', $ppp['ports']);
+ foreach ($ports as $pid => $port) {
+ $port = get_real_interface($port);
+ if ($realif == $port) {
+ $found = true;
+ break;
+ }
+ /* Find the parent interfaces of the vlans in the MLPPP configs
+ * there should be only one element in the array here
+ * -- this could be better . . . */
+ $parent_if = get_parent_interface($port);
+ if ($realif == $parent_if[0]) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ($found == false) {
+ $realif = get_real_interface($interface);
+ pfSense_ngctl_detach("{$realif}:", $realif);
+ }
+ /* NOTE: We make sure for this on interface_ppps_configure()
+ * no need to do it here again.
+ * else
+ * pfSense_ngctl_attach(".", $realif);
+ */
+}
+
+function interfaces_loopback_configure() {
+ global $g;
+
+ if (platform_booting()) {
+ echo gettext("Configuring loopback interface...");
+ }
+ pfSense_interface_setaddress("lo0", "127.0.0.1");
+ interfaces_bring_up("lo0");
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ return 0;
+}
+
+function interfaces_vlan_configure($realif = "") {
+ global $config, $g;
+ if (platform_booting()) {
+ echo gettext("Configuring VLAN interfaces...");
+ }
+ if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
+ foreach ($config['vlans']['vlan'] as $vlan) {
+ if (empty($vlan['vlanif'])) {
+ $vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
+ }
+ if (!empty($realif) && $realif != $vlan['vlanif']) {
+ continue;
+ }
+
+ /* XXX: Maybe we should report any errors?! */
+ interface_vlan_configure($vlan);
+ }
+ }
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+}
+
+function interface_vlan_configure(&$vlan) {
+ global $config, $g;
+
+ if (!is_array($vlan)) {
+ log_error(gettext("VLAN: called with wrong options. Problems with config!"));
+ return;
+ }
+ $if = $vlan['if'];
+ $vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
+ $tag = $vlan['tag'];
+
+ if (empty($if)) {
+ log_error(gettext("interface_vlan_configure called with if undefined."));
+ return;
+ }
+
+ /* make sure the parent interface is up */
+ interfaces_bring_up($if);
+ /* Since we are going to add vlan(4) try to enable all that hardware supports. */
+ pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
+
+ if (!empty($vlanif) && does_interface_exist($vlanif)) {
+ interface_bring_down($vlanif, true);
+ } else {
+ $tmpvlanif = pfSense_interface_create("vlan");
+ pfSense_interface_rename($tmpvlanif, $vlanif);
+ pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
+ }
+
+ pfSense_vlan_create($vlanif, $if, $tag);
+
+ interfaces_bring_up($vlanif);
+
+ /* invalidate interface cache */
+ get_interface_arr(true);
+
+ /* XXX: ermal -- for now leave it here at the moment it does not hurt. */
+ interfaces_bring_up($if);
+
+ return $vlanif;
+}
+
+function interface_qinq_configure(&$vlan, $fd = NULL) {
+ global $config, $g;
+
+ if (!is_array($vlan)) {
+ log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
+ return;
+ }
+
+ $qinqif = $vlan['if'];
+ $tag = $vlan['tag'];
+ if (empty($qinqif)) {
+ log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
+ return;
+ }
+
+ if (!does_interface_exist($qinqif)) {
+ log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
+ return;
+ }
+
+ $vlanif = interface_vlan_configure($vlan);
+
+ if ($fd == NULL) {
+ $exec = true;
+ $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
+ } else {
+ $exec = false;
+ }
+ /* make sure the parent is converted to ng_vlan(4) and is up */
+ interfaces_bring_up($qinqif);
+
+ pfSense_ngctl_attach(".", $qinqif);
+ if (!empty($vlanif) && does_interface_exist($vlanif)) {
+ fwrite($fd, "shutdown {$qinqif}qinq:\n");
+ exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
+ if (empty($result)) {
+ fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
+ fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
+ fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
+ }
+ } else {
+ fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
+ fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
+ fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
+ }
+
+ /* invalidate interface cache */
+ get_interface_arr(true);
+
+ if (!stristr($qinqif, "_vlan")) {
+ mwexec("/sbin/ifconfig {$qinqif} promisc\n");
+ }
+
+ $macaddr = get_interface_mac($qinqif);
+ if (!empty($vlan['members'])) {
+ $members = explode(" ", $vlan['members']);
+ foreach ($members as $qtag) {
+ $qinq = array();
+ $qinq['tag'] = $qtag;
+ $qinq['if'] = $vlanif;
+ interface_qinq2_configure($qinq, $fd, $macaddr);
+ }
+ }
+ if ($exec == true) {
+ fclose($fd);
+ mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
+ }
+
+ interfaces_bring_up($qinqif);
+ if (!empty($vlan['members'])) {
+ $members = explode(" ", $vlan['members']);
+ foreach ($members as $qif) {
+ interfaces_bring_up("{$vlanif}_{$qif}");
+ }
+ }
+
+ return $vlanif;
+}
+
+function interfaces_qinq_configure() {
+ global $config, $g;
+ if (platform_booting()) {
+ echo gettext("Configuring QinQ interfaces...");
+ }
+ if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
+ foreach ($config['qinqs']['qinqentry'] as $qinq) {
+ /* XXX: Maybe we should report any errors?! */
+ interface_qinq_configure($qinq);
+ }
+ }
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+}
+
+function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
+ global $config, $g;
+
+ if (!is_array($qinq)) {
+ log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
+ return;
+ }
+
+ $if = $qinq['if'];
+ $tag = $qinq['tag'];
+ $vlanif = "{$if}_{$tag}";
+ if (empty($if)) {
+ log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
+ return;
+ }
+
+ fwrite($fd, "shutdown {$if}h{$tag}:\n");
+ fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
+ fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
+ fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
+ fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
+ fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
+
+ /* invalidate interface cache */
+ get_interface_arr(true);
+
+ return $vlanif;
+}
+
+function interfaces_create_wireless_clones() {
+ global $config, $g;
+
+ if (platform_booting()) {
+ echo gettext("Creating wireless clone interfaces...");
+ }
+
+ $iflist = get_configured_interface_list();
+
+ foreach ($iflist as $if) {
+ $realif = $config['interfaces'][$if]['if'];
+ if (is_interface_wireless($realif)) {
+ interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
+ }
+ }
+
+ if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
+ foreach ($config['wireless']['clone'] as $clone) {
+ if (empty($clone['cloneif'])) {
+ continue;
+ }
+ if (does_interface_exist($clone['cloneif'])) {
+ continue;
+ }
+ /* XXX: Maybe we should report any errors?! */
+ interface_wireless_clone($clone['cloneif'], $clone);
+ }
+ }
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+
+}
+
+function interfaces_bridge_configure($checkmember = 0, $realif = "") {
+ global $config;
+
+ $i = 0;
+ if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
+ foreach ($config['bridges']['bridged'] as $bridge) {
+ if (empty($bridge['bridgeif'])) {
+ $bridge['bridgeif'] = "bridge{$i}";
+ }
+ if (!empty($realif) && $realif != $bridge['bridgeif']) {
+ continue;
+ }
+
+ if ($checkmember == 1) {
+ /* XXX: It should not be possible no? */
+ if (strstr($bridge['if'], '_vip')) {
+ continue;
+ }
+ $members = explode(',', $bridge['members']);
+ foreach ($members as $member) {
+ if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
+ continue 2;
+ }
+ }
+ }
+ else if ($checkmember == 2) {
+ $members = explode(',', $bridge['members']);
+ foreach ($members as $member) {
+ if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
+ continue 2;
+ }
+ }
+ }
+ /* XXX: Maybe we should report any errors?! */
+ interface_bridge_configure($bridge, $checkmember);
+ $i++;
+ }
+ }
+}
+
+function interface_bridge_configure(&$bridge, $checkmember = 0) {
+ global $config, $g;
+
+ if (!is_array($bridge)) {
+ return;
+ }
+
+ if (empty($bridge['members'])) {
+ log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
+ return;
+ }
+
+ $members = explode(',', $bridge['members']);
+ if (!count($members)) {
+ return;
+ }
+
+ /* Calculate smaller mtu and enforce it */
+ $smallermtu = 0;
+ $commonrx = true;
+ $commontx = true;
+ $foundgif = false;
+ foreach ($members as $member) {
+ $realif = get_real_interface($member);
+ $mtu = get_interface_mtu($realif);
+ if (substr($realif, 0, 3) == "gif") {
+ $foundgif = true;
+ if ($checkmember == 1) {
+ return;
+ }
+ if ($mtu <= 1500) {
+ continue;
+ }
+ }
+ if ($smallermtu == 0 && !empty($mtu)) {
+ $smallermtu = $mtu;
+ } else if (!empty($mtu) && $mtu < $smallermtu) {
+ $smallermtu = $mtu;
+ }
+ }
+ if ($foundgif == false && $checkmember == 2) {
+ return;
+ }
+
+ /* Just in case anything is not working well */
+ if ($smallermtu == 0) {
+ $smallermtu = 1500;
+ }
+
+ if (platform_booting() || !empty($bridge['bridgeif'])) {
+ pfSense_interface_destroy($bridge['bridgeif']);
+ pfSense_interface_create($bridge['bridgeif']);
+ $bridgeif = escapeshellarg($bridge['bridgeif']);
+ } else {
+ $bridgeif = pfSense_interface_create("bridge");
+ $bridge['bridgeif'] = $bridgeif;
+ }
+
+ $bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
+ if ($bridgemtu > $smallermtu) {
+ $smallermtu = $bridgemtu;
+ }
+
+ $checklist = get_configured_interface_list();
+
+ /* Add interfaces to bridge */
+ foreach ($members as $member) {
+ if (empty($checklist[$member])) {
+ continue;
+ }
+ $realif = get_real_interface($member);
+ if (!$realif) {
+ log_error(gettext("realif not defined in interfaces bridge - up"));
+ continue;
+ }
+ /* make sure the parent interface is up */
+ pfSense_interface_mtu($realif, $smallermtu);
+ interfaces_bring_up($realif);
+ enable_hardware_offloading($member);
+ pfSense_bridge_add_member($bridge['bridgeif'], $realif);
+ }
+
+ if (isset($bridge['enablestp'])) {
+ /* Choose spanning tree proto */
+ mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
+
+ if (!empty($bridge['stp'])) {
+ $stpifs = explode(',', $bridge['stp']);
+ foreach ($stpifs as $stpif) {
+ $realif = get_real_interface($stpif);
+ mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
+ }
+ }
+ if (!empty($bridge['maxage'])) {
+ mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
+ }
+ if (!empty($bridge['fwdelay'])) {
+ mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
+ }
+ if (!empty($bridge['hellotime'])) {
+ mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
+ }
+ if (!empty($bridge['priority'])) {
+ mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
+ }
+ if (!empty($bridge['holdcnt'])) {
+ mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
+ }
+ if (!empty($bridge['ifpriority'])) {
+ $pconfig = explode(",", $bridge['ifpriority']);
+ $ifpriority = array();
+ foreach ($pconfig as $cfg) {
+ $embcfg = explode_assoc(":", $cfg);
+ foreach ($embcfg as $key => $value) {
+ $ifpriority[$key] = $value;
+ }
+ }
+ foreach ($ifpriority as $key => $value) {
+ $realif = get_real_interface($key);
+ mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
+ }
+ }
+ if (!empty($bridge['ifpathcost'])) {
+ $pconfig = explode(",", $bridge['ifpathcost']);
+ $ifpathcost = array();
+ foreach ($pconfig as $cfg) {
+ $embcfg = explode_assoc(":", $cfg);
+ foreach ($embcfg as $key => $value) {
+ $ifpathcost[$key] = $value;
+ }
+ }
+ foreach ($ifpathcost as $key => $value) {
+ $realif = get_real_interface($key);
+ mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
+ }
+ }
+ }
+
+ if ($bridge['maxaddr'] <> "") {
+ mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
+ }
+ if ($bridge['timeout'] <> "") {
+ mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
+ }
+ if ($bridge['span'] <> "") {
+ $realif = get_real_interface($bridge['span']);
+ mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
+ }
+ if (!empty($bridge['edge'])) {
+ $edgeifs = explode(',', $bridge['edge']);
+ foreach ($edgeifs as $edgeif) {
+ $realif = get_real_interface($edgeif);
+ mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
+ }
+ }
+ if (!empty($bridge['autoedge'])) {
+ $edgeifs = explode(',', $bridge['autoedge']);
+ foreach ($edgeifs as $edgeif) {
+ $realif = get_real_interface($edgeif);
+ mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
+ }
+ }
+ if (!empty($bridge['ptp'])) {
+ $ptpifs = explode(',', $bridge['ptp']);
+ foreach ($ptpifs as $ptpif) {
+ $realif = get_real_interface($ptpif);
+ mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
+ }
+ }
+ if (!empty($bridge['autoptp'])) {
+ $ptpifs = explode(',', $bridge['autoptp']);
+ foreach ($ptpifs as $ptpif) {
+ $realif = get_real_interface($ptpif);
+ mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
+ }
+ }
+ if (!empty($bridge['static'])) {
+ $stickyifs = explode(',', $bridge['static']);
+ foreach ($stickyifs as $stickyif) {
+ $realif = get_real_interface($stickyif);
+ mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
+ }
+ }
+ if (!empty($bridge['private'])) {
+ $privateifs = explode(',', $bridge['private']);
+ foreach ($privateifs as $privateif) {
+ $realif = get_real_interface($privateif);
+ mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
+ }
+ }
+
+ if ($bridge['bridgeif']) {
+ interfaces_bring_up($bridge['bridgeif']);
+ } else {
+ log_error(gettext("bridgeif not defined -- could not bring interface up"));
+ }
+}
+
+function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
+
+ if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
+ return;
+ }
+
+ if ($flagsapplied == false) {
+ $mtu = get_interface_mtu($bridgeif);
+ $mtum = get_interface_mtu($interface);
+ if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
+ pfSense_interface_mtu($interface, $mtu);
+ }
+
+ hardware_offloading_applyflags($interface);
+ interfaces_bring_up($interface);
+ }
+
+ pfSense_bridge_add_member($bridgeif, $interface);
+}
+
+function interfaces_lagg_configure($realif = "") {
+ global $config, $g;
+ if (platform_booting()) {
+ echo gettext("Configuring LAGG interfaces...");
+ }
+ $i = 0;
+ if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
+ foreach ($config['laggs']['lagg'] as $lagg) {
+ if (empty($lagg['laggif'])) {
+ $lagg['laggif'] = "lagg{$i}";
+ }
+ if (!empty($realif) && $realif != $lagg['laggif']) {
+ continue;
+ }
+ /* XXX: Maybe we should report any errors?! */
+ interface_lagg_configure($lagg);
+ $i++;
+ }
+ }
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+}
+
+function interface_lagg_configure($lagg) {
+ global $config, $g;
+
+ if (!is_array($lagg)) {
+ return -1;
+ }
+
+ $members = explode(',', $lagg['members']);
+ if (!count($members)) {
+ return -1;
+ }
+
+ if (platform_booting() || !(empty($lagg['laggif']))) {
+ pfSense_interface_destroy($lagg['laggif']);
+ pfSense_interface_create($lagg['laggif']);
+ $laggif = $lagg['laggif'];
+ } else {
+ $laggif = pfSense_interface_create("lagg");
+ }
+
+ /* Check if MTU was defined for this lagg interface */
+ $lagg_mtu = interface_find_child_cfgmtu($laggif);
+ if ($lagg_mtu == 0) {
+ /* Calculate smaller mtu and enforce it */
+ $smallermtu = 0;
+ foreach ($members as $member) {
+ $mtu = get_interface_mtu($member);
+ if ($smallermtu == 0 && !empty($mtu)) {
+ $smallermtu = $mtu;
+ } else if (!empty($mtu) && $mtu < $smallermtu) {
+ $smallermtu = $mtu;
+ }
+ }
+ $lagg_mtu = $smallermtu;
+ }
+
+ /* Just in case anything is not working well */
+ if ($lagg_mtu == 0) {
+ $lagg_mtu = 1500;
+ }
+
+ foreach ($members as $member) {
+ if (!does_interface_exist($member)) {
+ continue;
+ }
+ /* make sure the parent interface is up */
+ pfSense_interface_mtu($member, $lagg_mtu);
+ interfaces_bring_up($member);
+ hardware_offloading_applyflags($member);
+ mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
+ }
+ pfSense_interface_capabilities($laggif, -$flags_off);
+ pfSense_interface_capabilities($laggif, $flags_on);
+
+ mwexec("/sbin/ifconfig {$laggif} laggproto " . escapeshellarg($lagg['proto']));
+
+ interfaces_bring_up($laggif);
+
+ return $laggif;
+}
+
+function interfaces_gre_configure($checkparent = 0, $realif = "") {
+ global $config;
+
+ if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
+ foreach ($config['gres']['gre'] as $i => $gre) {
+ if (empty($gre['greif'])) {
+ $gre['greif'] = "gre{$i}";
+ }
+ if (!empty($realif) && $realif != $gre['greif']) {
+ continue;
+ }
+
+ if ($checkparent == 1) {
+ if (substr($gre['if'], 0, 4) == '_vip') {
+ continue;
+ }
+ if (substr($gre['if'], 0, 5) == '_lloc') {
+ continue;
+ }
+ if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
+ continue;
+ }
+ } else if ($checkparent == 2) {
+ if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
+ (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
+ continue;
+ }
+ }
+ /* XXX: Maybe we should report any errors?! */
+ interface_gre_configure($gre);
+ }
+ }
+}
+
+/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
+function interface_gre_configure(&$gre, $grekey = "") {
+ global $config, $g;
+
+ if (!is_array($gre)) {
+ return -1;
+ }
+
+ $realif = get_real_interface($gre['if']);
+ $realifip = get_interface_ip($gre['if']);
+
+ /* make sure the parent interface is up */
+ interfaces_bring_up($realif);
+
+ if (platform_booting() || !(empty($gre['greif']))) {
+ pfSense_interface_destroy($gre['greif']);
+ pfSense_interface_create($gre['greif']);
+ $greif = $gre['greif'];
+ } else {
+ $greif = pfSense_interface_create("gre");
+ }
+
+ /* Do not change the order here for more see gre(4) NOTES section. */
+ mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
+ if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
+ /* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
+ //mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
+ mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
+ } else {
+ mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
+ }
+ if (isset($gre['link0'])) {
+ pfSense_interface_flags($greif, IFF_LINK0);
+ }
+ if (isset($gre['link1'])) {
+ pfSense_interface_flags($greif, IFF_LINK1);
+ }
+ if (isset($gre['link2'])) {
+ pfSense_interface_flags($greif, IFF_LINK2);
+ }
+
+ if ($greif) {
+ interfaces_bring_up($greif);
+ } else {
+ log_error(gettext("Could not bring greif up -- variable not defined."));
+ }
+
+ if (isset($gre['link1']) && $gre['link1']) {
+ mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
+ }
+ if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
+ file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
+ }
+ if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
+ file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
+ }
+
+ interfaces_bring_up($greif);
+
+ return $greif;
+}
+
+function interfaces_gif_configure($checkparent = 0, $realif = "") {
+ global $config;
+
+ if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
+ foreach ($config['gifs']['gif'] as $i => $gif) {
+ if (empty($gif['gifif'])) {
+ $gre['gifif'] = "gif{$i}";
+ }
+ if (!empty($realif) && $realif != $gif['gifif']) {
+ continue;
+ }
+
+ if ($checkparent == 1) {
+ if (substr($gif['if'], 0, 4) == '_vip') {
+ continue;
+ }
+ if (substr($gif['if'], 0, 5) == '_lloc') {
+ continue;
+ }
+ if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
+ continue;
+ }
+ }
+ else if ($checkparent == 2) {
+ if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
+ (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
+ continue;
+ }
+ }
+ /* XXX: Maybe we should report any errors?! */
+ interface_gif_configure($gif);
+ }
+ }
+}
+
+/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
+function interface_gif_configure(&$gif, $gifkey = "") {
+ global $config, $g;
+
+ if (!is_array($gif)) {
+ return -1;
+ }
+
+ $realif = get_real_interface($gif['if']);
+ $ipaddr = get_interface_ip($gif['if']);
+
+ if (is_ipaddrv4($gif['remote-addr'])) {
+ if (is_ipaddrv4($ipaddr)) {
+ $realifip = $ipaddr;
+ } else {
+ $realifip = get_interface_ip($gif['if']);
+ }
+ $realifgw = get_interface_gateway($gif['if']);
+ } else if (is_ipaddrv6($gif['remote-addr'])) {
+ if (is_ipaddrv6($ipaddr)) {
+ $realifip = $ipaddr;
+ } else {
+ $realifip = get_interface_ipv6($gif['if']);
+ }
+ $realifgw = get_interface_gateway_v6($gif['if']);
+ }
+ /* make sure the parent interface is up */
+ if ($realif) {
+ interfaces_bring_up($realif);
+ } else {
+ log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
+ }
+
+ if (platform_booting() || !(empty($gif['gifif']))) {
+ pfSense_interface_destroy($gif['gifif']);
+ pfSense_interface_create($gif['gifif']);
+ $gifif = $gif['gifif'];
+ } else {
+ $gifif = pfSense_interface_create("gif");
+ }
+
+ /* Do not change the order here for more see gif(4) NOTES section. */
+ mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
+ if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
+ /* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
+ //mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
+ mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
+ } else {
+ mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
+ }
+ if (isset($gif['link0'])) {
+ pfSense_interface_flags($gifif, IFF_LINK0);
+ }
+ if (isset($gif['link1'])) {
+ pfSense_interface_flags($gifif, IFF_LINK1);
+ }
+ if ($gifif) {
+ interfaces_bring_up($gifif);
+ } else {
+ log_error(gettext("could not bring gifif up -- variable not defined"));
+ }
+
+ if (!platform_booting()) {
+ $iflist = get_configured_interface_list();
+ foreach ($iflist as $ifname) {
+ if ($config['interfaces'][$ifname]['if'] == $gifif) {
+ if (get_interface_gateway($ifname)) {
+ system_routing_configure($ifname);
+ break;
+ }
+ if (get_interface_gateway_v6($ifname)) {
+ system_routing_configure($ifname);
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
+ file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
+ }
+ if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
+ file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
+ }
+
+ if (is_ipaddrv4($realifgw)) {
+ mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
+ }
+ if (is_ipaddrv6($realifgw)) {
+ mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
+ }
+
+ interfaces_bring_up($gifif);
+
+ return $gifif;
+}
+
+function interfaces_configure() {
+ global $config, $g;
+
+ /* Set up our loopback interface */
+ interfaces_loopback_configure();
+
+ /* create the unconfigured wireless clones */
+ interfaces_create_wireless_clones();
+
+ /* set up LAGG virtual interfaces */
+ interfaces_lagg_configure();
+
+ /* set up VLAN virtual interfaces */
+ interfaces_vlan_configure();
+
+ interfaces_qinq_configure();
+
+ $iflist = get_configured_interface_with_descr();
+ $delayed_list = array();
+ $bridge_list = array();
+ $track6_list = array();
+
+ /* This is needed to speedup interfaces on bootup. */
+ $reload = false;
+ if (!platform_booting()) {
+ $reload = true;
+ }
+
+ foreach ($iflist as $if => $ifname) {
+ $realif = $config['interfaces'][$if]['if'];
+ if (strstr($realif, "bridge")) {
+ $bridge_list[$if] = $ifname;
+ } else if (strstr($realif, "gre")) {
+ $delayed_list[$if] = $ifname;
+ } else if (strstr($realif, "gif")) {
+ $delayed_list[$if] = $ifname;
+ } else if (strstr($realif, "ovpn")) {
+ //echo "Delaying OpenVPN interface configuration...done.\n";
+ continue;
+ } else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
+ $track6_list[$if] = $ifname;
+ } else {
+ if (platform_booting()) {
+ printf(gettext("Configuring %s interface..."), $ifname);
+ }
+
+ if ($g['debug']) {
+ log_error(sprintf(gettext("Configuring %s"), $ifname));
+ }
+ interface_configure($if, $reload);
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+ }
+
+ /*
+ * NOTE: The following function parameter consists of
+ * 1 - Do not load gre/gif/bridge with parent/member as vip
+ * 2 - Do load gre/gif/bridge with parent/member as vip
+ */
+
+ /* set up GRE virtual interfaces */
+ interfaces_gre_configure(1);
+
+ /* set up GIF virtual interfaces */
+ interfaces_gif_configure(1);
+
+ /* set up BRIDGe virtual interfaces */
+ interfaces_bridge_configure(1);
+
+ foreach ($track6_list as $if => $ifname) {
+ if (platform_booting()) {
+ printf(gettext("Configuring %s interface..."), $ifname);
+ }
+ if ($g['debug']) {
+ log_error(sprintf(gettext("Configuring %s"), $ifname));
+ }
+
+ interface_configure($if, $reload);
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ /* bring up vip interfaces */
+ interfaces_vips_configure();
+
+ /* set up GRE virtual interfaces */
+ interfaces_gre_configure(2);
+
+ /* set up GIF virtual interfaces */
+ interfaces_gif_configure(2);
+
+ foreach ($delayed_list as $if => $ifname) {
+ if (platform_booting()) {
+ printf(gettext("Configuring %s interface..."), $ifname);
+ }
+ if ($g['debug']) {
+ log_error(sprintf(gettext("Configuring %s"), $ifname));
+ }
+
+ interface_configure($if, $reload);
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ /* set up BRIDGe virtual interfaces */
+ interfaces_bridge_configure(2);
+
+ foreach ($bridge_list as $if => $ifname) {
+ if (platform_booting()) {
+ printf(gettext("Configuring %s interface..."), $ifname);
+ }
+ if ($g['debug']) {
+ log_error(sprintf(gettext("Configuring %s"), $ifname));
+ }
+
+ interface_configure($if, $reload);
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ /* configure interface groups */
+ interfaces_group_setup();
+
+ if (!platform_booting()) {
+ /* reconfigure static routes (kernel may have deleted them) */
+ system_routing_configure();
+
+ /* reload IPsec tunnels */
+ vpn_ipsec_configure();
+
+ /* reload dhcpd (interface enabled/disabled status may have changed) */
+ services_dhcpd_configure();
+
+ /* restart dnsmasq or unbound */
+ if (isset($config['dnsmasq']['enable'])) {
+ services_dnsmasq_configure();
+ } elseif (isset($config['unbound']['enable'])) {
+ services_unbound_configure();
+ }
+ }
+
+ return 0;
+}
+
+function interface_reconfigure($interface = "wan", $reloadall = false) {
+ interface_bring_down($interface);
+ interface_configure($interface, $reloadall);
+}
+
+function interface_vip_bring_down($vip) {
+ global $g;
+
+ if (strpos($vip['interface'], '_vip')) {
+ if (is_ipaddrv6($vip['subnet'])) {
+ $family = 'inet6';
+ } else {
+ $family = 'inet';
+ }
+
+ $carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
+ $iface = $carpvip['interface'];
+ } else {
+ $iface = $vip['interface'];
+ }
+
+ $vipif = get_real_interface($iface);
+ switch ($vip['mode']) {
+ case "proxyarp":
+ if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
+ killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
+ }
+ break;
+ case "ipalias":
+ if (does_interface_exist($vipif)) {
+ if (is_ipaddrv6($vip['subnet'])) {
+ mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
+ } else {
+ pfSense_interface_deladdress($vipif, $vip['subnet']);
+ }
+ }
+ break;
+ case "carp":
+ /* XXX: Is enough to delete ip address? */
+ if (does_interface_exist($vipif)) {
+ if (is_ipaddrv6($vip['subnet'])) {
+ mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
+ } else {
+ pfSense_interface_deladdress($vipif, $vip['subnet']);
+ }
+ }
+ break;
+ }
+}
+
+function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
+ global $config, $g;
+
+ if (!isset($config['interfaces'][$interface])) {
+ return;
+ }
+
+ if ($g['debug']) {
+ log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
+ }
+
+ /*
+ * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
+ * In this case the real $realif of v4 is different from that of v6 for operation.
+ * Keep this in mind while doing changes here!
+ */
+ if ($ifacecfg === false) {
+ $ifcfg = $config['interfaces'][$interface];
+ $ppps = $config['ppps']['ppp'];
+ $realif = get_real_interface($interface);
+ $realifv6 = get_real_interface($interface, "inet6", true);
+ } elseif (!is_array($ifacecfg)) {
+ log_error(gettext("Wrong parameters used during interface_bring_down"));
+ $ifcfg = $config['interfaces'][$interface];
+ $ppps = $config['ppps']['ppp'];
+ $realif = get_real_interface($interface);
+ $realifv6 = get_real_interface($interface, "inet6", true);
+ } else {
+ $ifcfg = $ifacecfg['ifcfg'];
+ $ppps = $ifacecfg['ppps'];
+ if (isset($ifacecfg['ifcfg']['realif'])) {
+ $realif = $ifacecfg['ifcfg']['realif'];
+ /* XXX: Any better way? */
+ $realifv6 = $realif;
+ } else {
+ $realif = get_real_interface($interface);
+ $realifv6 = get_real_interface($interface, "inet6", true);
+ }
+ }
+
+ switch ($ifcfg['ipaddr']) {
+ case "ppp":
+ case "pppoe":
+ case "pptp":
+ case "l2tp":
+ if (is_array($ppps) && count($ppps)) {
+ foreach ($ppps as $pppid => $ppp) {
+ if ($realif == $ppp['if']) {
+ if (isset($ppp['ondemand']) && !$destroy) {
+ send_event("interface reconfigure {$interface}");
+ break;
+ }
+ if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
+ killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
+ sleep(2);
+ }
+ unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
+ break;
+ }
+ }
+ }
+ break;
+ case "dhcp":
+ kill_dhclient_process($realif);
+ unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
+ if (does_interface_exist("$realif")) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
+ interface_ipalias_cleanup($interface);
+ if ($destroy == true) {
+ pfSense_interface_flags($realif, -IFF_UP);
+ }
+ mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
+ }
+ break;
+ default:
+ if (does_interface_exist("$realif")) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
+ interface_ipalias_cleanup($interface);
+ if ($destroy == true) {
+ pfSense_interface_flags($realif, -IFF_UP);
+ }
+ mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
+ }
+ break;
+ }
+
+ $track6 = array();
+ switch ($ifcfg['ipaddrv6']) {
+ case "slaac":
+ case "dhcp6":
+ $pidv6 = find_dhcp6c_process($realif);
+ if ($pidv6) {
+ posix_kill($pidv6, SIGTERM);
+ }
+ sleep(3);
+ unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
+ unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
+ unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
+ if (does_interface_exist($realifv6)) {
+ $ip6 = find_interface_ipv6($realifv6);
+ if (is_ipaddrv6($ip6) && $ip6 != "::") {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
+ }
+ interface_ipalias_cleanup($interface, "inet6");
+ if ($destroy == true) {
+ pfSense_interface_flags($realif, -IFF_UP);
+ }
+ //mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
+ }
+ $track6 = link_interface_to_track6($interface);
+ break;
+ case "6rd":
+ case "6to4":
+ $realif = "{$interface}_stf";
+ if (does_interface_exist("$realif")) {
+ /* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
+ if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
+ ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
+ $destroy = true;
+ } else {
+ /* get_interface_ipv6() returns empty value if interface is being disabled */
+ $ip6 = get_interface_ipv6($interface);
+ if (is_ipaddrv6($ip6)) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
+ }
+ }
+ interface_ipalias_cleanup($interface, "inet6");
+ if ($destroy == true) {
+ pfSense_interface_flags($realif, -IFF_UP);
+ }
+ }
+ $track6 = link_interface_to_track6($interface);
+ break;
+ default:
+ if (does_interface_exist("$realif")) {
+ $ip6 = get_interface_ipv6($interface);
+ if (is_ipaddrv6($ip6)) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
+ }
+ if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
+ }
+ interface_ipalias_cleanup($interface, "inet6");
+ if ($destroy == true) {
+ pfSense_interface_flags($realif, -IFF_UP);
+ }
+ //mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
+ }
+ $track6 = link_interface_to_track6($interface);
+ break;
+ }
+
+ if (!empty($track6) && is_array($track6)) {
+ if (!function_exists('services_dhcpd_configure')) {
+ require_once('services.inc');
+ }
+ /* Bring down radvd and dhcp6 on these interfaces */
+ services_dhcpd_configure('inet6', $track6);
+ }
+
+ $old_router = '';
+ if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
+ $old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
+ }
+
+ /* remove interface up file if it exists */
+ unlink_if_exists("{$g['tmp_path']}/{$realif}up");
+ unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
+ unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
+ unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
+ unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
+ unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
+ unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
+
+ /* hostapd and wpa_supplicant do not need to be running when the interface is down.
+ * They will also use 100% CPU if running after the wireless clone gets deleted. */
+ if (is_array($ifcfg['wireless'])) {
+ kill_hostapd($realif);
+ mwexec(kill_wpasupplicant($realif));
+ }
+
+ if ($destroy == true) {
+ if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
+ pfSense_interface_destroy($realif);
+ }
+ }
+
+ return;
+}
+
+function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
+ global $config;
+ if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
+ unset($config["virtualip_carp_maintenancemode"]);
+ write_config("Leave CARP maintenance mode");
+ } else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
+ $config["virtualip_carp_maintenancemode"] = true;
+ write_config("Enter CARP maintenance mode");
+ }
+
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ if ($vip['mode'] == "carp") {
+ interface_carp_configure($vip);
+ }
+ }
+}
+
+function interface_isppp_type($interface) {
+ global $config;
+
+ if (!is_array($config['interfaces'][$interface])) {
+ return false;
+ }
+
+ switch ($config['interfaces'][$interface]['ipaddr']) {
+ case 'pptp':
+ case 'l2tp':
+ case 'pppoe':
+ case 'ppp':
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+}
+
+function interfaces_ptpid_used($ptpid) {
+ global $config;
+
+ if (is_array($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as & $settings) {
+ if ($ptpid == $settings['ptpid']) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function interfaces_ptpid_next() {
+
+ $ptpid = 0;
+ while (interfaces_ptpid_used($ptpid)) {
+ $ptpid++;
+ }
+
+ return $ptpid;
+}
+
+function getMPDCRONSettings($pppif) {
+ global $config;
+
+ $cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
+ if (is_array($config['cron']['item'])) {
+ foreach ($config['cron']['item'] as $i => $item) {
+ if (stripos($item['command'], $cron_cmd_file) !== false) {
+ return array("ID" => $i, "ITEM" => $item);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+function handle_pppoe_reset($post_array) {
+ global $config, $g;
+
+ $pppif = "{$post_array['type']}{$post_array['ptpid']}";
+ $cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
+
+ if (!is_array($config['cron']['item'])) {
+ $config['cron']['item'] = array();
+ }
+
+ $itemhash = getMPDCRONSettings($pppif);
+
+ // reset cron items if necessary and return
+ if (empty($post_array['pppoe-reset-type'])) {
+ if (isset($itemhash)) {
+ unset($config['cron']['item'][$itemhash['ID']]);
+ }
+ sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
+ return;
+ }
+
+ if (empty($itemhash)) {
+ $itemhash = array();
+ }
+ $item = array();
+ if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
+ $item['minute'] = $post_array['pppoe_resetminute'];
+ $item['hour'] = $post_array['pppoe_resethour'];
+ if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
+ $date = explode("/", $post_array['pppoe_resetdate']);
+ $item['mday'] = $date[1];
+ $item['month'] = $date[0];
+ } else {
+ $item['mday'] = "*";
+ $item['month'] = "*";
+ }
+ $item['wday'] = "*";
+ $item['who'] = "root";
+ $item['command'] = $cron_cmd_file;
+ } else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
+ switch ($post_array['pppoe_pr_preset_val']) {
+ case "monthly":
+ $item['minute'] = "0";
+ $item['hour'] = "0";
+ $item['mday'] = "1";
+ $item['month'] = "*";
+ $item['wday'] = "*";
+ break;
+ case "weekly":
+ $item['minute'] = "0";
+ $item['hour'] = "0";
+ $item['mday'] = "*";
+ $item['month'] = "*";
+ $item['wday'] = "0";
+ break;
+ case "daily":
+ $item['minute'] = "0";
+ $item['hour'] = "0";
+ $item['mday'] = "*";
+ $item['month'] = "*";
+ $item['wday'] = "*";
+ break;
+ case "hourly":
+ $item['minute'] = "0";
+ $item['hour'] = "*";
+ $item['mday'] = "*";
+ $item['month'] = "*";
+ $item['wday'] = "*";
+ break;
+ } // end switch
+ $item['who'] = "root";
+ $item['command'] = $cron_cmd_file;
+ }
+ if (empty($item)) {
+ return;
+ }
+ if (isset($itemhash['ID'])) {
+ $config['cron']['item'][$itemhash['ID']] = $item;
+ } else {
+ $config['cron']['item'][] = $item;
+ }
+}
+
+/*
+ * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
+ * It writes the mpd config file to /var/etc every time the link is opened.
+ */
+function interface_ppps_configure($interface) {
+ global $config, $g;
+
+ /* Return for unassigned interfaces. This is a minimum requirement. */
+ if (empty($config['interfaces'][$interface])) {
+ return 0;
+ }
+ $ifcfg = $config['interfaces'][$interface];
+ if (!isset($ifcfg['enable'])) {
+ return 0;
+ }
+
+ // mpd5 requires a /var/spool/lock directory for PPP modem links.
+ if (!is_dir("/var/spool/lock")) {
+ mkdir("/var/spool/lock", 0777, true);
+ }
+ // mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
+ if (!file_exists("{$g['varetc_path']}/mpd.script")) {
+ @symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
+ }
+
+ if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
+ if ($ifcfg['if'] == $ppp['if']) {
+ break;
+ }
+ }
+ }
+ if (!$ppp || $ifcfg['if'] != $ppp['if']) {
+ log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
+ return 0;
+ }
+ $pppif = $ifcfg['if'];
+ if ($ppp['type'] == "ppp") {
+ $type = "modem";
+ } else {
+ $type = $ppp['type'];
+ }
+ $upper_type = strtoupper($ppp['type']);
+
+ /* XXX: This does not make sense and may create trouble
+ * comment it for now to be removed later on.
+ if (platform_booting()) {
+ $descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
+ echo "starting {$pppif} link...";
+ if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
+ return 0;
+ }
+ */
+
+ $ports = explode(',', $ppp['ports']);
+ if ($type != "modem") {
+ foreach ($ports as $pid => $port) {
+ $ports[$pid] = get_real_interface($port);
+ if (empty($ports[$pid])) {
+ return 0;
+ }
+ }
+ }
+ $localips = explode(',', $ppp['localip']);
+ $gateways = explode(',', $ppp['gateway']);
+ $subnets = explode(',', $ppp['subnet']);
+
+ /* We bring up the parent interface first because if DHCP is configured on the parent we need
+ * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
+ */
+ foreach ($ports as $pid => $port) {
+ switch ($ppp['type']) {
+ case "pppoe":
+ /* Bring the parent interface up */
+ interfaces_bring_up($port);
+ pfSense_ngctl_attach(".", $port);
+ /* Enable setautosrc to automatically change mac address if parent interface's changes */
+ mwexec("ngctl msg {$port}: setautosrc 1");
+ break;
+ case "pptp":
+ case "l2tp":
+ /* configure interface */
+ if (is_ipaddr($localips[$pid])) {
+ // Manually configure interface IP/subnet
+ pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
+ interfaces_bring_up($port);
+ } else if (empty($localips[$pid])) {
+ $localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
+ }
+
+ if (!is_ipaddr($localips[$pid])) {
+ log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
+ $localips[$pid] = "0.0.0.0";
+ }
+ if (!is_ipaddr($gateways[$pid])) {
+ log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
+ return 0;
+ }
+ pfSense_ngctl_attach(".", $port);
+ break;
+ case "ppp":
+ if (!file_exists("{$port}")) {
+ log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
+ return 0;
+ }
+ break;
+ default:
+ log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
+ break;
+ }
+ }
+
+ if (is_array($ports) && count($ports) > 1) {
+ $multilink = "enable";
+ } else {
+ $multilink = "disable";
+ }
+
+ if ($type == "modem") {
+ if (is_ipaddr($ppp['localip'])) {
+ $localip = $ppp['localip'];
+ } else {
+ $localip = '0.0.0.0';
+ }
+
+ if (is_ipaddr($ppp['gateway'])) {
+ $gateway = $ppp['gateway'];
+ } else {
+ $gateway = "10.64.64.{$pppid}";
+ }
+ $ranges = "{$localip}/0 {$gateway}/0";
+
+ if (empty($ppp['apnum'])) {
+ $ppp['apnum'] = 1;
+ }
+ } else {
+ $ranges = "0.0.0.0/0 0.0.0.0/0";
+ }
+
+ if (isset($ppp['ondemand'])) {
+ $ondemand = "enable";
+ } else {
+ $ondemand = "disable";
+ }
+ if (!isset($ppp['idletimeout'])) {
+ $ppp['idletimeout'] = 0;
+ }
+
+ if (empty($ppp['username']) && $type == "modem") {
+ $ppp['username'] = "user";
+ $ppp['password'] = "none";
+ }
+ if (empty($ppp['password']) && $type == "modem") {
+ $passwd = "none";
+ } else {
+ $passwd = base64_decode($ppp['password']);
+ }
+
+ $bandwidths = explode(',', $ppp['bandwidth']);
+ $defaultmtu = "1492";
+ if (!empty($ifcfg['mtu'])) {
+ $defaultmtu = intval($ifcfg['mtu']);
+ }
+ $mtus = explode(',', $ppp['mtu']);
+ $mrus = explode(',', $ppp['mru']);
+
+ if (isset($ppp['mrru'])) {
+ $mrrus = explode(',', $ppp['mrru']);
+ }
+
+ // Construct the mpd.conf file
+ $mpdconf = <<<EOD
+startup:
+ # configure the console
+ set console close
+ # configure the web server
+ set web close
+
+default:
+{$ppp['type']}client:
+ create bundle static {$interface}
+ set bundle enable ipv6cp
+ set iface name {$pppif}
+
+EOD;
+ $setdefaultgw = false;
+ $founddefaultgw = false;
+ if (is_array($config['gateways']['gateway_item'])) {
+ foreach ($config['gateways']['gateway_item'] as $gateway) {
+ if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
+ $setdefaultgw = true;
+ break;
+ } else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
+ $founddefaultgw = true;
+ break;
+ }
+ }
+ }
+
+ if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
+ $setdefaultgw = true;
+ $mpdconf .= <<<EOD
+ set iface route default
+
+EOD;
+ }
+ $mpdconf .= <<<EOD
+ set iface {$ondemand} on-demand
+ set iface idle {$ppp['idletimeout']}
+
+EOD;
+
+ if (isset($ppp['ondemand'])) {
+ $mpdconf .= <<<EOD
+ set iface addrs 10.10.1.1 10.10.1.2
+
+EOD;
+ }
+
+ if (isset($ppp['tcpmssfix'])) {
+ $tcpmss = "disable";
+ } else {
+ $tcpmss = "enable";
+ }
+ $mpdconf .= <<<EOD
+ set iface {$tcpmss} tcpmssfix
+
+EOD;
+
+ $mpdconf .= <<<EOD
+ set iface up-script /usr/local/sbin/ppp-linkup
+ set iface down-script /usr/local/sbin/ppp-linkdown
+ set ipcp ranges {$ranges}
+
+EOD;
+ if (isset($ppp['vjcomp'])) {
+ $mpdconf .= <<<EOD
+ set ipcp no vjcomp
+
+EOD;
+ }
+
+ if (isset($config['system']['dnsallowoverride'])) {
+ $mpdconf .= <<<EOD
+ set ipcp enable req-pri-dns
+ set ipcp enable req-sec-dns
+
+EOD;
+ }
+
+ if (!isset($ppp['verbose_log'])) {
+ $mpdconf .= <<<EOD
+ #log -bund -ccp -chat -iface -ipcp -lcp -link
+
+EOD;
+ }
+
+ foreach ($ports as $pid => $port) {
+ $port = get_real_interface($port);
+ $mpdconf .= <<<EOD
+
+ create link static {$interface}_link{$pid} {$type}
+ set link action bundle {$interface}
+ set link {$multilink} multilink
+ set link keep-alive 10 60
+ set link max-redial 0
+
+EOD;
+ if (isset($ppp['shortseq'])) {
+ $mpdconf .= <<<EOD
+ set link no shortseq
+
+EOD;
+ }
+
+ if (isset($ppp['acfcomp'])) {
+ $mpdconf .= <<<EOD
+ set link no acfcomp
+
+EOD;
+ }
+
+ if (isset($ppp['protocomp'])) {
+ $mpdconf .= <<<EOD
+ set link no protocomp
+
+EOD;
+ }
+
+ $mpdconf .= <<<EOD
+ set link disable chap pap
+ set link accept chap pap eap
+ set link disable incoming
+
+EOD;
+
+
+ if (!empty($bandwidths[$pid])) {
+ $mpdconf .= <<<EOD
+ set link bandwidth {$bandwidths[$pid]}
+
+EOD;
+ }
+
+ if (empty($mtus[$pid])) {
+ $mtus[$pid] = $defaultmtu;
+ }
+ $mpdconf .= <<<EOD
+ set link mtu {$mtus[$pid]}
+
+EOD;
+
+ if (!empty($mrus[$pid])) {
+ $mpdconf .= <<<EOD
+ set link mru {$mrus[$pid]}
+
+EOD;
+ }
+
+ if (!empty($mrrus[$pid])) {
+ $mpdconf .= <<<EOD
+ set link mrru {$mrrus[$pid]}
+
+EOD;
+ }
+
+ $mpdconf .= <<<EOD
+ set auth authname "{$ppp['username']}"
+ set auth password {$passwd}
+
+EOD;
+ if ($type == "modem") {
+ $mpdconf .= <<<EOD
+ set modem device {$ppp['ports']}
+ set modem script DialPeer
+ set modem idle-script Ringback
+ set modem watch -cd
+ set modem var \$DialPrefix "DT"
+ set modem var \$Telephone "{$ppp['phone']}"
+
+EOD;
+ }
+ if (isset($ppp['connect-timeout']) && $type == "modem") {
+ $mpdconf .= <<<EOD
+ set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
+
+EOD;
+ }
+ if (isset($ppp['initstr']) && $type == "modem") {
+ $initstr = base64_decode($ppp['initstr']);
+ $mpdconf .= <<<EOD
+ set modem var \$InitString "{$initstr}"
+
+EOD;
+ }
+ if (isset($ppp['simpin']) && $type == "modem") {
+ if ($ppp['pin-wait'] == "") {
+ $ppp['pin-wait'] = 0;
+ }
+ $mpdconf .= <<<EOD
+ set modem var \$SimPin "{$ppp['simpin']}"
+ set modem var \$PinWait "{$ppp['pin-wait']}"
+
+EOD;
+ }
+ if (isset($ppp['apn']) && $type == "modem") {
+ $mpdconf .= <<<EOD
+ set modem var \$APN "{$ppp['apn']}"
+ set modem var \$APNum "{$ppp['apnum']}"
+
+EOD;
+ }
+ if ($type == "pppoe") {
+ // Send a null service name if none is set.
+ $provider = isset($ppp['provider']) ? $ppp['provider'] : "";
+ $mpdconf .= <<<EOD
+ set pppoe service "{$provider}"
+
+EOD;
+ }
+ if ($type == "pppoe") {
+ $mpdconf .= <<<EOD
+ set pppoe iface {$port}
+
+EOD;
+ }
+
+ if ($type == "pptp" || $type == "l2tp") {
+ $mpdconf .= <<<EOD
+ set {$type} self {$localips[$pid]}
+ set {$type} peer {$gateways[$pid]}
+
+EOD;
+ }
+
+ $mpdconf .= "\topen\n";
+ } //end foreach ($port)
+
+
+ /* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
+ if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
+ @symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
+ } else {
+ $fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
+ if (!$fd) {
+ log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
+ return 0;
+ }
+ // Write out mpd_ppp.conf
+ fwrite($fd, $mpdconf);
+ fclose($fd);
+ unset($mpdconf);
+ }
+
+ // Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
+ if (isset($ppp['uptime'])) {
+ if (!file_exists("/conf/{$pppif}.log")) {
+ conf_mount_rw();
+ file_put_contents("/conf/{$pppif}.log", '');
+ conf_mount_ro();
+ }
+ } else {
+ if (file_exists("/conf/{$pppif}.log")) {
+ conf_mount_rw();
+ @unlink("/conf/{$pppif}.log");
+ conf_mount_ro();
+ }
+ }
+
+ /* clean up old lock files */
+ foreach ($ports as $port) {
+ if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
+ unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
+ }
+ }
+
+ /* fire up mpd */
+ mwexec("/usr/local/sbin/mpd5 -b -k -d {$g['varetc_path']} -f mpd_{$interface}.conf -p {$g['varrun_path']}/" .
+ escapeshellarg($ppp['type']) . "_{$interface}.pid -s ppp " . escapeshellarg($ppp['type']) . "client");
+
+ // Check for PPPoE periodic reset request
+ if ($type == "pppoe") {
+ if (!empty($ppp['pppoe-reset-type'])) {
+ interface_setup_pppoe_reset_file($ppp['if'], $interface);
+ } else {
+ interface_setup_pppoe_reset_file($ppp['if']);
+ }
+ }
+ /* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
+ $i = 0;
+ while ($i < 3) {
+ sleep(10);
+ if (does_interface_exist($ppp['if'], true)) {
+ break;
+ }
+ $i++;
+ }
+
+ /* we only support the 3gstats.php for huawei modems for now. Will add more later. */
+ /* We should be able to launch the right version for each modem */
+ /* We can also guess the mondev from the manufacturer */
+ exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
+ mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
+ foreach ($ports as $port) {
+ if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
+ $mondev = substr(basename($port), 0, -1);
+ $devlist = glob("/dev/{$mondev}?");
+ $mondev = basename(end($devlist));
+ }
+ if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
+ $mondev = substr(basename($port), 0, -1) . "1";
+ }
+ if ($mondev != '') {
+ log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
+ mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
+ }
+ }
+
+ return 1;
+}
+
+function interfaces_sync_setup() {
+ global $g, $config;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "interfaces_sync_setup() being called $mt\n";
+ }
+
+ if (platform_booting()) {
+ echo gettext("Configuring CARP settings...");
+ mute_kernel_msgs();
+ }
+
+ /* suck in configuration items */
+ if ($config['hasync']) {
+ $pfsyncenabled = $config['hasync']['pfsyncenabled'];
+ $pfsyncinterface = $config['hasync']['pfsyncinterface'];
+ $pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
+ } else {
+ unset($pfsyncinterface);
+ unset($pfsyncenabled);
+ }
+
+ set_sysctl(array(
+ "net.inet.carp.preempt" => "1",
+ "net.inet.carp.log" => "1")
+ );
+
+ if (!empty($pfsyncinterface)) {
+ $carp_sync_int = get_real_interface($pfsyncinterface);
+ } else {
+ unset($carp_sync_int);
+ }
+
+ /* setup pfsync interface */
+ if (isset($carp_sync_int) and isset($pfsyncenabled)) {
+ if (is_ipaddr($pfsyncpeerip)) {
+ $syncpeer = "syncpeer {$pfsyncpeerip}";
+ } else {
+ $syncpeer = "-syncpeer";
+ }
+
+ mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
+ mwexec("/sbin/ifconfig pfsync0 -defer", false);
+
+ sleep(1);
+
+ /* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
+ * for existing sessions.
+ */
+ log_error("waiting for pfsync...");
+ $i = 0;
+ while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
+ $i++;
+ sleep(1);
+ }
+ log_error("pfsync done in $i seconds.");
+ log_error("Configuring CARP settings finalize...");
+ } else {
+ mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
+ }
+
+ if ($config['virtualip']['vip']) {
+ set_single_sysctl("net.inet.carp.allow", "1");
+ } else {
+ set_single_sysctl("net.inet.carp.allow", "0");
+ }
+
+ if (platform_booting()) {
+ unmute_kernel_msgs();
+ echo gettext("done.") . "\n";
+ }
+}
+
+function interface_proxyarp_configure($interface = "") {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "interface_proxyarp_configure() being called $mt\n";
+ }
+
+ /* kill any running choparp */
+ if (empty($interface)) {
+ killbyname("choparp");
+ } else {
+ $vipif = get_real_interface($interface);
+ if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
+ killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
+ }
+ }
+
+ $paa = array();
+ if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
+
+ /* group by interface */
+ foreach ($config['virtualip']['vip'] as $vipent) {
+ if ($vipent['mode'] === "proxyarp") {
+ if ($vipent['interface']) {
+ $proxyif = $vipent['interface'];
+ } else {
+ $proxyif = "wan";
+ }
+
+ if (!empty($interface) && $interface != $proxyif) {
+ continue;
+ }
+
+ if (!is_array($paa[$proxyif])) {
+ $paa[$proxyif] = array();
+ }
+
+ $paa[$proxyif][] = $vipent;
+ }
+ }
+ }
+
+ if (!empty($interface)) {
+ if (is_array($paa[$interface])) {
+ $paaifip = get_interface_ip($interface);
+ if (!is_ipaddr($paaifip)) {
+ return;
+ }
+ $args = get_real_interface($interface) . " auto";
+ foreach ($paa[$interface] as $paent) {
+ if (isset($paent['subnet'])) {
+ $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
+ } else if (isset($paent['range'])) {
+ $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
+ }
+ }
+ mwexec_bg("/usr/local/sbin/choparp " . $args);
+ }
+ } else if (count($paa) > 0) {
+ foreach ($paa as $paif => $paents) {
+ $paaifip = get_interface_ip($paif);
+ if (!is_ipaddr($paaifip)) {
+ continue;
+ }
+ $args = get_real_interface($paif) . " auto";
+ foreach ($paents as $paent) {
+ if (isset($paent['subnet'])) {
+ $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
+ } else if (isset($paent['range'])) {
+ $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
+ }
+ }
+ mwexec_bg("/usr/local/sbin/choparp " . $args);
+ }
+ }
+}
+
+function interface_ipalias_cleanup($interface, $inet = "inet4") {
+ global $g, $config;
+
+ if (is_array($config['virtualip']['vip'])) {
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
+ if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
+ interface_vip_bring_down($vip);
+ } else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
+ interface_vip_bring_down($vip);
+ }
+ }
+ }
+ }
+}
+
+function interfaces_vips_configure($interface = "") {
+ global $g, $config;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "interfaces_vips_configure() being called $mt\n";
+ }
+ $paa = array();
+ if (is_array($config['virtualip']['vip'])) {
+ $carp_setuped = false;
+ $anyproxyarp = false;
+ foreach ($config['virtualip']['vip'] as $vip) {
+ switch ($vip['mode']) {
+ case "proxyarp":
+ /* nothing it is handled on interface_proxyarp_configure() */
+ if ($interface <> "" && $vip['interface'] <> $interface) {
+ continue;
+ }
+ $anyproxyarp = true;
+ break;
+ case "ipalias":
+ if ($interface <> "" && $vip['interface'] <> $interface) {
+ continue;
+ }
+ interface_ipalias_configure($vip);
+ break;
+ case "carp":
+ if ($interface <> "" && $vip['interface'] <> $interface) {
+ continue;
+ }
+ if ($carp_setuped == false) {
+ $carp_setuped = true;
+ }
+ interface_carp_configure($vip);
+ break;
+ }
+ }
+ if ($carp_setuped == true) {
+ interfaces_sync_setup();
+ }
+ if ($anyproxyarp == true) {
+ interface_proxyarp_configure();
+ }
+ }
+}
+
+function interface_ipalias_configure(&$vip) {
+ global $config;
+
+ if ($vip['mode'] != 'ipalias') {
+ return;
+ }
+
+ if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
+ if (!isset($config['interfaces'][$vip['interface']])) {
+ return;
+ }
+
+ if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
+ return;
+ }
+ }
+
+ $af = 'inet';
+ if (is_ipaddrv6($vip['subnet'])) {
+ $af = 'inet6';
+ }
+ $iface = $vip['interface'];
+ $vipadd = '';
+ if (strpos($vip['interface'], '_vip')) {
+ $carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
+ $iface = $carpvip['interface'];
+ $vipadd = "vhid {$carpvip['vhid']}";
+ }
+ $if = get_real_interface($iface);
+ mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
+ unset($iface, $af, $if, $carpvip, $vipadd);
+}
+
+function interface_reload_carps($cif) {
+ global $config;
+
+ $carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
+ if (empty($carpifs)) {
+ return;
+ }
+
+ $carps = explode(" ", $carpifs);
+ if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ if (in_array($vip['carpif'], $carps)) {
+ switch ($vip['mode']) {
+ case "carp":
+ interface_vip_bring_down($vip);
+ sleep(1);
+ interface_carp_configure($vip);
+ break;
+ case "ipalias":
+ interface_vip_bring_down($vip);
+ sleep(1);
+ interface_ipalias_configure($vip);
+ break;
+ }
+ }
+ }
+ }
+}
+
+function interface_carp_configure(&$vip) {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "interface_carp_configure() being called $mt\n";
+ }
+
+ if ($vip['mode'] != "carp") {
+ return;
+ }
+
+ /* NOTE: Maybe its useless nowadays */
+ $realif = get_real_interface($vip['interface']);
+ if (!does_interface_exist($realif)) {
+ file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
+ return;
+ }
+
+ $vip_password = $vip['password'];
+ $vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
+ if ($vip['password'] != "") {
+ $password = " pass {$vip_password}";
+ }
+
+ $advbase = "";
+ if (!empty($vip['advbase'])) {
+ $advbase = "advbase " . escapeshellarg($vip['advbase']);
+ }
+
+ $carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
+ if ($carp_maintenancemode) {
+ $advskew = "advskew 254";
+ } else {
+ $advskew = "advskew " . escapeshellarg($vip['advskew']);
+ }
+
+ mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
+
+ if (is_ipaddrv4($vip['subnet'])) {
+ mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
+ } else if (is_ipaddrv6($vip['subnet'])) {
+ mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
+ }
+
+ return $realif;
+}
+
+function interface_wireless_clone($realif, $wlcfg) {
+ global $config, $g;
+ /* Check to see if interface has been cloned as of yet.
+ * If it has not been cloned then go ahead and clone it.
+ */
+ $needs_clone = false;
+ if (is_array($wlcfg['wireless'])) {
+ $wlcfg_mode = $wlcfg['wireless']['mode'];
+ } else {
+ $wlcfg_mode = $wlcfg['mode'];
+ }
+ switch ($wlcfg_mode) {
+ case "hostap":
+ $mode = "wlanmode hostap";
+ break;
+ case "adhoc":
+ $mode = "wlanmode adhoc";
+ break;
+ default:
+ $mode = "";
+ break;
+ }
+ $baseif = interface_get_wireless_base($wlcfg['if']);
+ if (does_interface_exist($realif)) {
+ exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
+ $ifconfig_str = implode($output);
+ if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
+ log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
+ $needs_clone = true;
+ }
+ if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
+ log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
+ $needs_clone = true;
+ }
+ if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
+ log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
+ $needs_clone = true;
+ }
+ } else {
+ $needs_clone = true;
+ }
+
+ if ($needs_clone == true) {
+ /* remove previous instance if it exists */
+ if (does_interface_exist($realif)) {
+ pfSense_interface_destroy($realif);
+ }
+
+ log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
+ // Create the new wlan interface. FreeBSD returns the new interface name.
+ // example: wlan2
+ exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
+ if ($ret <> 0) {
+ log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
+ return false;
+ }
+ $newif = trim($out[0]);
+ // Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
+ pfSense_interface_rename($newif, $realif);
+ file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
+ }
+ return true;
+}
+
+function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
+ global $config, $g;
+
+ $shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
+ 'diversity', 'txantenna', 'rxantenna', 'distance',
+ 'regdomain', 'regcountry', 'reglocation');
+
+ if (!is_interface_wireless($ifcfg['if'])) {
+ return;
+ }
+
+ $baseif = interface_get_wireless_base($ifcfg['if']);
+
+ // Sync shared settings for assigned clones
+ $iflist = get_configured_interface_list(false, true);
+ foreach ($iflist as $if) {
+ if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
+ if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
+ foreach ($shared_settings as $setting) {
+ if ($sync_changes) {
+ if (isset($ifcfg['wireless'][$setting])) {
+ $config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
+ } else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
+ unset($config['interfaces'][$if]['wireless'][$setting]);
+ }
+ } else {
+ if (isset($config['interfaces'][$if]['wireless'][$setting])) {
+ $ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
+ } else if (isset($ifcfg['wireless'][$setting])) {
+ unset($ifcfg['wireless'][$setting]);
+ }
+ }
+ }
+ if (!$sync_changes) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Read or write settings at shared area
+ if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
+ foreach ($shared_settings as $setting) {
+ if ($sync_changes) {
+ if (isset($ifcfg['wireless'][$setting])) {
+ $config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
+ } else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
+ unset($config['wireless']['interfaces'][$baseif][$setting]);
+ }
+ } else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
+ if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
+ $ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
+ } else if (isset($ifcfg['wireless'][$setting])) {
+ unset($ifcfg['wireless'][$setting]);
+ }
+ }
+ }
+ }
+
+ // Sync the mode on the clone creation page with the configured mode on the interface
+ if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
+ foreach ($config['wireless']['clone'] as &$clone) {
+ if ($clone['cloneif'] == $ifcfg['if']) {
+ if ($sync_changes) {
+ $clone['mode'] = $ifcfg['wireless']['mode'];
+ } else {
+ $ifcfg['wireless']['mode'] = $clone['mode'];
+ }
+ break;
+ }
+ }
+ unset($clone);
+ }
+}
+
+function interface_wireless_configure($if, &$wl, &$wlcfg) {
+ global $config, $g;
+
+ /* open up a shell script that will be used to output the commands.
+ * since wireless is changing a lot, these series of commands are fragile
+ * and will sometimes need to be verified by a operator by executing the command
+ * and returning the output of the command to the developers for inspection. please
+ * do not change this routine from a shell script to individual exec commands. -sullrich
+ */
+
+ // Remove script file
+ unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
+
+ // Clone wireless nic if needed.
+ interface_wireless_clone($if, $wl);
+
+ // Reject inadvertent changes to shared settings in case the interface hasn't been configured.
+ interface_sync_wireless_clones($wl, false);
+
+ $fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh", "w");
+ fwrite($fd_set, "#!/bin/sh\n");
+ fwrite($fd_set, "# {$g['product_name']} wireless configuration script.\n\n");
+
+ $wlan_setup_log = fopen("{$g['tmp_path']}/{$if}_setup.log", "w");
+
+ /* set values for /path/program */
+ $hostapd = "/usr/sbin/hostapd";
+ $wpa_supplicant = "/usr/sbin/wpa_supplicant";
+ $ifconfig = "/sbin/ifconfig";
+ $sysctl = "/sbin/sysctl";
+ $killall = "/usr/bin/killall";
+
+ /* Set all wireless ifconfig variables (split up to get rid of needed checking) */
+
+ $wlcmd = array();
+ $wl_sysctl = array();
+ /* Make sure it's up */
+ $wlcmd[] = "up";
+ /* Set a/b/g standard */
+ $standard = str_replace(" Turbo", "", $wlcfg['standard']);
+ /* skip mode entirely for "auto" */
+ if ($wlcfg['standard'] != "auto") {
+ $wlcmd[] = "mode " . escapeshellarg($standard);
+ }
+
+ /* XXX: Disable ampdu for now on mwl when running in 11n mode
+ * to prevent massive packet loss under certain conditions. */
+ if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
+ $wlcmd[] = "-ampdu";
+ }
+
+ /* Set ssid */
+ if ($wlcfg['ssid']) {
+ $wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
+ }
+
+ /* Set 802.11g protection mode */
+ $wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
+
+ /* set wireless channel value */
+ if (isset($wlcfg['channel'])) {
+ if ($wlcfg['channel'] == "0") {
+ $wlcmd[] = "channel any";
+ } else {
+ $wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
+ }
+ }
+
+ /* Set antenna diversity value */
+ if (isset($wlcfg['diversity'])) {
+ $wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
+ }
+
+ /* Set txantenna value */
+ if (isset($wlcfg['txantenna'])) {
+ $wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
+ }
+
+ /* Set rxantenna value */
+ if (isset($wlcfg['rxantenna'])) {
+ $wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
+ }
+
+ /* set Distance value */
+ if ($wlcfg['distance']) {
+ $distance = escapeshellarg($wlcfg['distance']);
+ }
+
+ /* Set wireless hostap mode */
+ if ($wlcfg['mode'] == "hostap") {
+ $wlcmd[] = "mediaopt hostap";
+ } else {
+ $wlcmd[] = "-mediaopt hostap";
+ }
+
+ /* Set wireless adhoc mode */
+ if ($wlcfg['mode'] == "adhoc") {
+ $wlcmd[] = "mediaopt adhoc";
+ } else {
+ $wlcmd[] = "-mediaopt adhoc";
+ }
+
+ /* Not necessary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
+
+ /* handle hide ssid option */
+ if (isset($wlcfg['hidessid']['enable'])) {
+ $wlcmd[] = "hidessid";
+ } else {
+ $wlcmd[] = "-hidessid";
+ }
+
+ /* handle pureg (802.11g) only option */
+ if (isset($wlcfg['pureg']['enable'])) {
+ $wlcmd[] = "mode 11g pureg";
+ } else {
+ $wlcmd[] = "-pureg";
+ }
+
+ /* handle puren (802.11n) only option */
+ if (isset($wlcfg['puren']['enable'])) {
+ $wlcmd[] = "puren";
+ } else {
+ $wlcmd[] = "-puren";
+ }
+
+ /* enable apbridge option */
+ if (isset($wlcfg['apbridge']['enable'])) {
+ $wlcmd[] = "apbridge";
+ } else {
+ $wlcmd[] = "-apbridge";
+ }
+
+ /* handle turbo option */
+ if (isset($wlcfg['turbo']['enable'])) {
+ $wlcmd[] = "mediaopt turbo";
+ } else {
+ $wlcmd[] = "-mediaopt turbo";
+ }
+
+ /* handle txpower setting */
+ // or don't. this has issues at the moment.
+ /*
+ if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
+ $wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
+ }*/
+
+ /* handle wme option */
+ if (isset($wlcfg['wme']['enable'])) {
+ $wlcmd[] = "wme";
+ } else {
+ $wlcmd[] = "-wme";
+ }
+
+ /* set up wep if enabled */
+ $wepset = "";
+ if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
+ switch ($wlcfg['wpa']['auth_algs']) {
+ case "1":
+ $wepset .= "authmode open wepmode on ";
+ break;
+ case "2":
+ $wepset .= "authmode shared wepmode on ";
+ break;
+ case "3":
+ $wepset .= "authmode mixed wepmode on ";
+ }
+ $i = 1;
+ foreach ($wlcfg['wep']['key'] as $wepkey) {
+ $wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
+ if (isset($wepkey['txkey'])) {
+ $wlcmd[] = "weptxkey {$i} ";
+ }
+ $i++;
+ }
+ $wlcmd[] = $wepset;
+ } else if (isset($wlcfg['wpa']['enable'])) {
+ $wlcmd[] = "authmode wpa wepmode off ";
+ } else {
+ $wlcmd[] = "authmode open wepmode off ";
+ }
+
+ kill_hostapd($if);
+ mwexec(kill_wpasupplicant("{$if}"));
+
+ /* generate wpa_supplicant/hostap config if wpa is enabled */
+ conf_mount_rw();
+
+ switch ($wlcfg['mode']) {
+ case 'bss':
+ if (isset($wlcfg['wpa']['enable'])) {
+ $wpa .= <<<EOD
+ctrl_interface={$g['varrun_path']}/wpa_supplicant
+ctrl_interface_group=0
+ap_scan=1
+#fast_reauth=1
+network={
+ssid="{$wlcfg['ssid']}"
+scan_ssid=1
+priority=5
+key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
+psk="{$wlcfg['wpa']['passphrase']}"
+pairwise={$wlcfg['wpa']['wpa_pairwise']}
+group={$wlcfg['wpa']['wpa_pairwise']}
+}
+EOD;
+
+ @file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
+ unset($wpa);
+ }
+ break;
+ case 'hostap':
+ if (!empty($wlcfg['wpa']['passphrase'])) {
+ $wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
+ } else {
+ $wpa_passphrase = "";
+ }
+ if (isset($wlcfg['wpa']['enable'])) {
+ $wpa .= <<<EOD
+interface={$if}
+driver=bsd
+logger_syslog=-1
+logger_syslog_level=0
+logger_stdout=-1
+logger_stdout_level=0
+dump_file={$g['tmp_path']}/hostapd_{$if}.dump
+ctrl_interface={$g['varrun_path']}/hostapd
+ctrl_interface_group=wheel
+#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
+#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
+#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
+ssid={$wlcfg['ssid']}
+debug={$wlcfg['wpa']['debug_mode']}
+auth_algs={$wlcfg['wpa']['auth_algs']}
+wpa={$wlcfg['wpa']['wpa_mode']}
+wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
+wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
+wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
+wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
+wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
+{$wpa_passphrase}
+
+EOD;
+
+ if (isset($wlcfg['wpa']['rsn_preauth'])) {
+ $wpa .= <<<EOD
+# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
+rsn_preauth=1
+rsn_preauth_interfaces={$if}
+
+EOD;
+ }
+ if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
+ $wpa .= "ieee8021x=1\n";
+
+ if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
+ $auth_server_port = "1812";
+ if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
+ $auth_server_port = intval($wlcfg['auth_server_port']);
+ }
+ $wpa .= <<<EOD
+
+auth_server_addr={$wlcfg['auth_server_addr']}
+auth_server_port={$auth_server_port}
+auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
+
+EOD;
+ if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
+ $auth_server_port2 = "1812";
+ if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
+ $auth_server_port2 = intval($wlcfg['auth_server_port2']);
+ }
+
+ $wpa .= <<<EOD
+auth_server_addr={$wlcfg['auth_server_addr2']}
+auth_server_port={$auth_server_port2}
+auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
+
+EOD;
+ }
+ }
+ }
+
+ @file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
+ unset($wpa);
+ }
+ break;
+ }
+
+ /*
+ * all variables are set, lets start up everything
+ */
+
+ $baseif = interface_get_wireless_base($if);
+ preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
+ $wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
+
+ /* set sysctls for the wireless interface */
+ if (!empty($wl_sysctl)) {
+ fwrite($fd_set, "# sysctls for {$baseif}\n");
+ foreach ($wl_sysctl as $wl_sysctl_line) {
+ fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
+ }
+ }
+
+ /* set ack timers according to users preference (if he/she has any) */
+ if ($distance) {
+ fwrite($fd_set, "# Enable ATH distance settings\n");
+ fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
+ }
+
+ if (isset($wlcfg['wpa']['enable'])) {
+ if ($wlcfg['mode'] == "bss") {
+ fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
+ }
+ if ($wlcfg['mode'] == "hostap") {
+ /* add line to script to restore old mac to make hostapd happy */
+ if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
+ $if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
+ if (is_macaddr($if_oldmac)) {
+ fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
+ " link " . escapeshellarg($if_oldmac) . "\n");
+ }
+ }
+
+ fwrite($fd_set, "{$hostapd} -B -P {$g['varrun_path']}/hostapd_{$if}.pid {$g['varetc_path']}/hostapd_{$if}.conf\n");
+
+ /* add line to script to restore spoofed mac after running hostapd */
+ if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
+ if ($wl['spoofmac']) {
+ $if_curmac = $wl['spoofmac'];
+ } else {
+ $if_curmac = get_interface_mac($if);
+ }
+ if (is_macaddr($if_curmac)) {
+ fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
+ " link " . escapeshellarg($if_curmac) . "\n");
+ }
+ }
+ }
+ }
+
+ fclose($fd_set);
+ conf_mount_ro();
+
+ /* Making sure regulatory settings have actually changed
+ * before applying, because changing them requires bringing
+ * down all wireless networks on the interface. */
+ exec("{$ifconfig} " . escapeshellarg($if), $output);
+ $ifconfig_str = implode($output);
+ unset($output);
+ $reg_changing = false;
+
+ /* special case for the debug country code */
+ if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
+ $reg_changing = true;
+ } else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
+ $reg_changing = true;
+ } else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
+ $reg_changing = true;
+ } else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
+ $reg_changing = true;
+ } else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
+ $reg_changing = true;
+ }
+
+ if ($reg_changing) {
+ /* set regulatory domain */
+ if ($wlcfg['regdomain']) {
+ $wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
+ }
+
+ /* set country */
+ if ($wlcfg['regcountry']) {
+ $wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
+ }
+
+ /* set location */
+ if ($wlcfg['reglocation']) {
+ $wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
+ }
+
+ $wlregcmd_args = implode(" ", $wlregcmd);
+
+ /* build a complete list of the wireless clones for this interface */
+ $clone_list = array();
+ if (does_interface_exist(interface_get_wireless_clone($baseif))) {
+ $clone_list[] = interface_get_wireless_clone($baseif);
+ }
+ if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
+ foreach ($config['wireless']['clone'] as $clone) {
+ if ($clone['if'] == $baseif) {
+ $clone_list[] = $clone['cloneif'];
+ }
+ }
+ }
+
+ /* find which clones are up and bring them down */
+ $clones_up = array();
+ foreach ($clone_list as $clone_if) {
+ $clone_status = pfSense_get_interface_addresses($clone_if);
+ if ($clone_status['status'] == 'up') {
+ $clones_up[] = $clone_if;
+ mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
+ }
+ }
+
+ /* apply the regulatory settings */
+ mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
+ fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
+
+ /* bring the clones back up that were previously up */
+ foreach ($clones_up as $clone_if) {
+ interfaces_bring_up($clone_if);
+
+ /*
+ * Rerun the setup script for the interface if it isn't this interface, the interface
+ * is in infrastructure mode, and WPA is enabled.
+ * This can be removed if wpa_supplicant stops dying when you bring the interface down.
+ */
+ if ($clone_if != $if) {
+ $friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
+ if ((!empty($friendly_if)) &&
+ ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
+ (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
+ mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
+ }
+ }
+ }
+ }
+
+ /* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set
+ * mode twice (for now at least). This can be removed entirely in the future if no problems are found
+
+ * The mode must be specified in a separate command before ifconfig
+ * will allow the mode and channel at the same time in the next. */
+ //mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
+ //fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
+
+ /* configure wireless */
+ $wlcmd_args = implode(" ", $wlcmd);
+ mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
+ fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
+ fclose($wlan_setup_log);
+
+ unset($wlcmd_args, $wlcmd);
+
+
+ sleep(1);
+ /* execute hostapd and wpa_supplicant if required in shell */
+ mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
+
+ return 0;
+
+}
+
+function kill_hostapd($interface) {
+ global $g;
+
+ if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
+ return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
+ }
+}
+
+function kill_wpasupplicant($interface) {
+ return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
+}
+
+function find_dhclient_process($interface) {
+ if ($interface) {
+ $pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
+ } else {
+ $pid = 0;
+ }
+
+ return intval($pid);
+}
+
+function kill_dhclient_process($interface) {
+ if (empty($interface) || !does_interface_exist($interface)) {
+ return;
+ }
+
+ $i = 0;
+ while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
+ /* 3rd time make it die for sure */
+ $sig = ($i == 2 ? SIGKILL : SIGTERM);
+ posix_kill($pid, $sig);
+ sleep(1);
+ $i++;
+ }
+ unset($i);
+}
+
+function find_dhcp6c_process($interface) {
+ global $g;
+
+ if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
+ $pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
+ } else {
+ return(false);
+ }
+
+ return intval($pid);
+}
+
+function interface_virtual_create($interface) {
+ global $config;
+
+ if (strstr($interface, "_vlan")) {
+ interfaces_vlan_configure($vlan);
+ } else if (substr($interface, 0, 3) == "gre") {
+ interfaces_gre_configure(0, $interface);
+ } else if (substr($interface, 0, 3) == "gif") {
+ interfaces_gif_configure(0, $interface);
+ } else if (substr($interface, 0, 5) == "ovpns") {
+ if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $server) {
+ if ($interface == "ovpns{$server['vpnid']}") {
+ if (!function_exists('openvpn_resync')) {
+ require_once('openvpn.inc');
+ }
+ log_error("OpenVPN: Resync server {$server['description']}");
+ openvpn_resync('server', $server);
+ }
+ }
+ unset($server);
+ }
+ } else if (substr($interface, 0, 5) == "ovpnc") {
+ if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as $client) {
+ if ($interface == "ovpnc{$client['vpnid']}") {
+ if (!function_exists('openvpn_resync')) {
+ require_once('openvpn.inc');
+ }
+ log_error("OpenVPN: Resync server {$client['description']}");
+ openvpn_resync('client', $client);
+ }
+ }
+ unset($client);
+ }
+ } else if (substr($interface, 0, 4) == "lagg") {
+ interfaces_lagg_configure($interface);
+ } else if (substr($interface, 0, 6) == "bridge") {
+ interfaces_bridge_configure(0, $interface);
+ }
+}
+
+function interface_vlan_mtu_configured($realhwif, $mtu) {
+ global $config;
+
+ if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
+ foreach ($config['vlans']['vlan'] as $vlan) {
+ if ($vlan['if'] != $realhwif) {
+ continue;
+ }
+ $assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
+ if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
+ if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
+ $mtu = $config['interfaces'][$assignedport]['mtu'];
+ }
+ }
+ }
+ }
+
+ return $mtu;
+}
+
+function interface_vlan_adapt_mtu($vlanifs, $mtu) {
+ global $config;
+
+ if (!is_array($vlanifs)) {
+ return;
+ }
+
+ /* All vlans need to use the same mtu value as their parent. */
+ foreach ($vlanifs as $vlan) {
+ $assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
+ if (!empty($assignedport)) {
+ if (!empty($config['interfaces'][$assignedport]['mtu'])) {
+ pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
+ } else {
+ if (get_interface_mtu($vlan['vlanif']) != $mtu) {
+ pfSense_interface_mtu($vlan['vlanif'], $mtu);
+ }
+ }
+ } else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
+ pfSense_interface_mtu($vlan['vlanif'], $mtu);
+ }
+ }
+}
+
+function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
+ global $config, $g;
+ global $interface_sn_arr_cache, $interface_ip_arr_cache;
+ global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
+
+ $wancfg = $config['interfaces'][$interface];
+
+ if (!isset($wancfg['enable'])) {
+ return;
+ }
+
+ $realif = get_real_interface($interface);
+ $realhwif_array = get_parent_interface($interface);
+ // Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
+ $realhwif = $realhwif_array[0];
+
+ if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
+ /* remove all IPv4 and IPv6 addresses */
+ $tmpifaces = pfSense_getall_interface_addresses($realif);
+ if (is_array($tmpifaces)) {
+ foreach ($tmpifaces as $tmpiface) {
+ if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
+ if (!is_linklocal($tmpiface)) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
+ }
+ } else {
+ if (is_subnetv4($tmpiface)) {
+ $tmpip = explode('/', $tmpiface);
+ $tmpip = $tmpip[0];
+ } else {
+ $tmpip = $tmpiface;
+ }
+ pfSense_interface_deladdress($realif, $tmpip);
+ }
+ }
+ }
+
+ /* only bring down the interface when both v4 and v6 are set to NONE */
+ if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
+ interface_bring_down($interface);
+ }
+ }
+
+ $interface_to_check = $realif;
+ if (interface_isppp_type($interface)) {
+ $interface_to_check = $realhwif;
+ }
+
+ /* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
+ if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) || !does_interface_exist($interface_to_check))) {
+ interface_virtual_create($interface_to_check);
+ }
+
+ /* Disable Accepting router advertisements unless specifically requested */
+ if ($g['debug']) {
+ log_error("Deny router advertisements for interface {$interface}");
+ }
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
+
+ /* wireless configuration? */
+ if (is_array($wancfg['wireless'])) {
+ interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
+ }
+
+ $mac = get_interface_mac($realhwif);
+ /*
+ * Don't try to reapply the spoofed MAC if it's already applied.
+ * When ifconfig link is used, it cycles the interface down/up, which triggers
+ * the interface config again, which attempts to spoof the MAC again,
+ * which cycles the link again...
+ */
+ if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
+ " link " . escapeshellarg($wancfg['spoofmac']));
+ } else {
+
+ if ($mac == "ff:ff:ff:ff:ff:ff") {
+ /* this is not a valid mac address. generate a
+ * temporary mac address so the machine can get online.
+ */
+ echo gettext("Generating new MAC address.");
+ $random_mac = generate_random_mac_address();
+ mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
+ " link " . escapeshellarg($random_mac));
+ $wancfg['spoofmac'] = $random_mac;
+ write_config();
+ file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
+ }
+ }
+
+ /* media */
+ if ($wancfg['media'] || $wancfg['mediaopt']) {
+ $cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
+ if ($wancfg['media']) {
+ $cmd .= " media " . escapeshellarg($wancfg['media']);
+ }
+ if ($wancfg['mediaopt']) {
+ $cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
+ }
+ mwexec($cmd);
+ }
+
+ /* Apply hw offloading policies as configured */
+ enable_hardware_offloading($interface);
+
+ /* invalidate interface/ip/sn cache */
+ get_interface_arr(true);
+ unset($interface_ip_arr_cache[$realif]);
+ unset($interface_sn_arr_cache[$realif]);
+ unset($interface_ipv6_arr_cache[$realif]);
+ unset($interface_snv6_arr_cache[$realif]);
+
+ $tunnelif = substr($realif, 0, 3);
+
+ if (does_interface_exist($wancfg['if'])) {
+ interfaces_bring_up($wancfg['if']);
+ }
+
+ if (!empty($wancfg['mtu'])) {
+ if (stristr($realif, "_vlan")) {
+ $assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
+ if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
+ $parentmtu = $config['interfaces'][$assignedparent]['mtu'];
+ if ($wancfg['mtu'] > $parentmtu) {
+ log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
+ }
+ } else {
+ $parentmtu = 0;
+ }
+
+ $parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
+
+ if (get_interface_mtu($realhwif) != $parentmtu) {
+ pfSense_interface_mtu($realhwif, $parentmtu);
+ }
+
+ /* All vlans need to use the same mtu value as their parent. */
+ interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
+ } else if (substr($realif, 0, 4) == 'lagg') {
+ /* LAGG interface must be destroyed and re-created to change MTU */
+ if ($wancfg['mtu'] != get_interface_mtu($realif)) {
+ if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
+ foreach ($config['laggs']['lagg'] as $lagg) {
+ if ($lagg['laggif'] == $realif) {
+ interface_lagg_configure($lagg);
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ if ($wancfg['mtu'] != get_interface_mtu($realif)) {
+ pfSense_interface_mtu($realif, $wancfg['mtu']);
+ }
+
+ /* This case is needed when the parent of vlans is being configured */
+ $vlans = link_interface_to_vlans($realif);
+ if (is_array($vlans)) {
+ interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
+ }
+ unset($vlans);
+ }
+ /* XXX: What about gre/gif/.. ? */
+ }
+
+ switch ($wancfg['ipaddr']) {
+ case 'dhcp':
+ interface_dhcp_configure($interface);
+ break;
+ case 'pppoe':
+ case 'l2tp':
+ case 'pptp':
+ case 'ppp':
+ interface_ppps_configure($interface);
+ break;
+ default:
+ /* XXX: Kludge for now related to #3280 */
+ if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
+ if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
+ pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
+ }
+ }
+ break;
+ }
+
+ switch ($wancfg['ipaddrv6']) {
+ case 'slaac':
+ case 'dhcp6':
+ interface_dhcpv6_configure($interface, $wancfg);
+ break;
+ case '6rd':
+ interface_6rd_configure($interface, $wancfg);
+ break;
+ case '6to4':
+ interface_6to4_configure($interface, $wancfg);
+ break;
+ case 'track6':
+ interface_track6_configure($interface, $wancfg, $linkupevent);
+ break;
+ default:
+ /* XXX: Kludge for now related to #3280 */
+ if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
+ if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
+ //pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
+ // FIXME: Add IPv6 Support to the pfSense module
+ mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
+ }
+ }
+ break;
+ }
+
+ interface_netgraph_needed($interface);
+
+ if (!platform_booting()) {
+ link_interface_to_vips($interface, "update");
+
+ if ($tunnelif != 'gre') {
+ unset($gre);
+ $gre = link_interface_to_gre($interface);
+ if (!empty($gre)) {
+ array_walk($gre, 'interface_gre_configure');
+ }
+ }
+
+ if ($tunnelif != 'gif') {
+ unset($gif);
+ $gif = link_interface_to_gif ($interface);
+ if (!empty($gif)) {
+ array_walk($gif, 'interface_gif_configure');
+ }
+ }
+
+ if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
+ unset($bridgetmp);
+ $bridgetmp = link_interface_to_bridge($interface);
+ if (!empty($bridgetmp)) {
+ interface_bridge_add_member($bridgetmp, $realif);
+ }
+ }
+
+ $grouptmp = link_interface_to_group($interface);
+ if (!empty($grouptmp)) {
+ array_walk($grouptmp, 'interface_group_add_member');
+ }
+
+ if ($interface == "lan") {
+ /* make new hosts file */
+ system_hosts_generate();
+ }
+
+ if ($reloadall == true) {
+
+ /* reconfigure static routes (kernel may have deleted them) */
+ system_routing_configure($interface);
+
+ /* reload ipsec tunnels */
+ send_event("service reload ipsecdns");
+
+ /* restart dnsmasq or unbound */
+ if (isset($config['dnsmasq']['enable'])) {
+ services_dnsmasq_configure();
+ } elseif (isset($config['unbound']['enable'])) {
+ services_unbound_configure();
+ }
+
+ /* update dyndns */
+ send_event("service reload dyndns {$interface}");
+
+ /* reload captive portal */
+ if (!function_exists('captiveportal_init_rules_byinterface')) {
+ require_once('captiveportal.inc');
+ }
+ captiveportal_init_rules_byinterface($interface);
+ }
+ }
+
+ interfaces_staticarp_configure($interface);
+ return 0;
+}
+
+function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
+ global $config, $g;
+
+ if (!is_array($wancfg)) {
+ return;
+ }
+
+ if (!isset($wancfg['enable'])) {
+ return;
+ }
+
+ /* If the interface is not configured via another, exit */
+ if (empty($wancfg['track6-interface'])) {
+ return;
+ }
+
+ /* always configure a link-local of fe80::1:1 on the track6 interfaces */
+ $realif = get_real_interface($interface);
+ $linklocal = find_interface_ipv6_ll($realif);
+ if (!empty($linklocal)) {
+ mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
+ }
+ /* XXX: This might break for good on a carp installation using link-local as network ips */
+ /* XXX: Probably should remove? */
+ mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
+
+ $trackcfg = $config['interfaces'][$wancfg['track6-interface']];
+ if (!isset($trackcfg['enable'])) {
+ log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
+ return;
+ }
+
+ switch ($trackcfg['ipaddrv6']) {
+ case "6to4":
+ if ($g['debug']) {
+ log_error("Interface {$interface} configured via {$wancfg['track6-interface']} type {$type}");
+ }
+ interface_track6_6to4_configure($interface, $wancfg);
+ break;
+ case "6rd":
+ if ($g['debug']) {
+ log_error("Interface {$interface} configured via {$wancfg['track6-interface']} type {$type}");
+ }
+ interface_track6_6rd_configure($interface, $wancfg);
+ break;
+ case "dhcp6":
+ if ($linkupevent == true) {
+ /*
+ * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
+ * Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
+ *
+ * XXX: Probably DHCPv6 client should handle this automagically itself?
+ */
+ $parentrealif = get_real_interface($wancfg['track6-interface']);
+ $pidv6 = find_dhcp6c_process($parentrealif);
+ if ($pidv6) {
+ posix_kill($pidv6, SIGHUP);
+ }
+ }
+ break;
+ }
+
+ if ($linkupevent == false) {
+ if (!function_exists('services_dhcpd_configure')) {
+ require_once("services.inc");
+ }
+
+ if (isset($config['unbound']['enable'])) {
+ services_unbound_configure();
+ }
+
+ services_dhcpd_configure("inet6");
+ }
+
+ return 0;
+}
+
+function interface_track6_6rd_configure($interface = "lan", $lancfg) {
+ global $config, $g;
+ global $interface_ipv6_arr_cache;
+ global $interface_snv6_arr_cache;
+
+ if (!is_array($lancfg)) {
+ return;
+ }
+
+ /* If the interface is not configured via another, exit */
+ if (empty($lancfg['track6-interface'])) {
+ return;
+ }
+
+ $wancfg = $config['interfaces'][$lancfg['track6-interface']];
+ if (empty($wancfg)) {
+ log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
+ return;
+ }
+
+ $ip4address = get_interface_ip($lancfg['track6-interface']);
+ if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
+ log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
+ return;
+ }
+ $hexwanv4 = return_hex_ipv4($ip4address);
+
+ /* create the long prefix notation for math, save the prefix length */
+ $rd6prefix = explode("/", $wancfg['prefix-6rd']);
+ $rd6prefixlen = $rd6prefix[1];
+ $rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
+
+ /* binary presentation of the prefix for all 128 bits. */
+ $rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
+
+ /* just save the left prefix length bits */
+ $rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
+ /* add the v4 address, offset n bits from the left */
+ $rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
+
+ /* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
+ /* 64 - (37 + (32 - 17)) = 8 == /52 */
+ $restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
+ // echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
+ $rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
+ /* fill the rest out with zeros */
+ $rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
+
+ /* convert the 128 bits for the lan address back into a valid IPv6 address */
+ $rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
+
+ $lanif = get_real_interface($interface);
+ $oip = find_interface_ipv6($lanif);
+ if (is_ipaddrv6($oip)) {
+ mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
+ }
+ unset($interface_ipv6_arr_cache[$lanif]);
+ unset($interface_snv6_arr_cache[$lanif]);
+ log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
+ mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
+
+ return 0;
+}
+
+function interface_track6_6to4_configure($interface = "lan", $lancfg) {
+ global $config, $g;
+ global $interface_ipv6_arr_cache;
+ global $interface_snv6_arr_cache;
+
+ if (!is_array($lancfg)) {
+ return;
+ }
+
+ /* If the interface is not configured via another, exit */
+ if (empty($lancfg['track6-interface'])) {
+ return;
+ }
+
+ $wancfg = $config['interfaces'][$lancfg['track6-interface']];
+ if (empty($wancfg)) {
+ log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
+ return;
+ }
+
+ $ip4address = get_interface_ip($lancfg['track6-interface']);
+ if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
+ log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
+ return;
+ }
+ $hexwanv4 = return_hex_ipv4($ip4address);
+
+ /* create the long prefix notation for math, save the prefix length */
+ $sixto4prefix = "2002::";
+ $sixto4prefixlen = 16;
+ $sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
+
+ /* binary presentation of the prefix for all 128 bits. */
+ $sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
+
+ /* just save the left prefix length bits */
+ $sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
+ /* add the v4 address */
+ $sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
+ /* add the custom prefix id */
+ $sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
+ /* fill the rest out with zeros */
+ $sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
+
+ /* convert the 128 bits for the lan address back into a valid IPv6 address */
+ $sixto4lan = convert_128bit_to_ipv6($sixto4lanbin) ."1";
+
+ $lanif = get_real_interface($interface);
+ $oip = find_interface_ipv6($lanif);
+ if (is_ipaddrv6($oip)) {
+ mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
+ }
+ unset($interface_ipv6_arr_cache[$lanif]);
+ unset($interface_snv6_arr_cache[$lanif]);
+ log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
+ mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
+
+ return 0;
+}
+
+function interface_6rd_configure($interface = "wan", $wancfg) {
+ global $config, $g;
+
+ /* because this is a tunnel interface we can only function
+ * with a public IPv4 address on the interface */
+
+ if (!is_array($wancfg)) {
+ return;
+ }
+
+ if (!is_module_loaded('if_stf.ko')) {
+ mwexec('/sbin/kldload if_stf.ko');
+ }
+
+ $wanif = get_real_interface($interface);
+ $ip4address = find_interface_ip($wanif);
+ if (!is_ipaddrv4($ip4address)) {
+ log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
+ return false;
+ }
+ $hexwanv4 = return_hex_ipv4($ip4address);
+
+ if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
+ $wancfg['prefix-6rd-v4plen'] = 0;
+ }
+
+ /* create the long prefix notation for math, save the prefix length */
+ $rd6prefix = explode("/", $wancfg['prefix-6rd']);
+ $rd6prefixlen = $rd6prefix[1];
+ $brgw = explode('.', $wancfg['gateway-6rd']);
+ $rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
+ $rd6brgw .= str_pad(decbin($brgw[0]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[1]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[2]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[3]), 8, '0', STR_PAD_LEFT);
+ if (strlen($rd6brgw) < 128) {
+ $rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
+ }
+ $rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
+ unset($brgw);
+ $rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
+
+ /* binary presentation of the prefix for all 128 bits. */
+ $rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
+
+ /* just save the left prefix length bits */
+ $rd6prefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
+ /* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
+ $rd6prefixbin .= substr(sprintf("%032b", hexdec($hexwanv4)), $wancfg['prefix-6rd-v4plen'], 32);
+ /* fill out the rest with 0's */
+ $rd6prefixbin = str_pad($rd6prefixbin, 128, "0", STR_PAD_RIGHT);
+
+ /* convert the 128 bits for the broker address back into a valid IPv6 address */
+ $rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
+
+
+ /* XXX: need to extend to support variable prefix size for v4 */
+ if (!is_module_loaded("if_stf")) {
+ mwexec("/sbin/kldload if_stf.ko");
+ }
+ $stfiface = "{$interface}_stf";
+ if (does_interface_exist($stfiface)) {
+ pfSense_interface_destroy($stfiface);
+ }
+ $tmpstfiface = pfSense_interface_create("stf");
+ pfSense_interface_rename($tmpstfiface, $stfiface);
+ pfSense_interface_flags($stfiface, IFF_LINK2);
+ mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
+ mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
+ if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
+ mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
+ }
+ if ($g['debug']) {
+ log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
+ }
+
+ /* write out a default router file */
+ file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
+ file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
+
+ $ip4gateway = get_interface_gateway($interface);
+ if (is_ipaddrv4($ip4gateway)) {
+ mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
+ }
+
+ /* configure dependent interfaces */
+ if (!platform_booting()) {
+ link_interface_to_track6($interface, "update");
+ }
+
+ return 0;
+}
+
+function interface_6to4_configure($interface = "wan", $wancfg) {
+ global $config, $g;
+
+ /* because this is a tunnel interface we can only function
+ * with a public IPv4 address on the interface */
+
+ if (!is_array($wancfg)) {
+ return;
+ }
+
+ $wanif = get_real_interface($interface);
+ $ip4address = find_interface_ip($wanif);
+ if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
+ log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
+ return false;
+ }
+
+ /* create the long prefix notation for math, save the prefix length */
+ $stfprefixlen = 16;
+ $stfprefix = Net_IPv6::uncompress("2002::");
+ $stfarr = explode(":", $stfprefix);
+ $v4prefixlen = "0";
+
+ /* we need the hex form of the interface IPv4 address */
+ $ip4arr = explode(".", $ip4address);
+ $hexwanv4 = "";
+ foreach ($ip4arr as $octet) {
+ $hexwanv4 .= sprintf("%02x", $octet);
+ }
+
+ /* we need the hex form of the broker IPv4 address */
+ $ip4arr = explode(".", "192.88.99.1");
+ $hexbrv4 = "";
+ foreach ($ip4arr as $octet) {
+ $hexbrv4 .= sprintf("%02x", $octet);
+ }
+
+ /* binary presentation of the prefix for all 128 bits. */
+ $stfprefixbin = "";
+ foreach ($stfarr as $element) {
+ $stfprefixbin .= sprintf("%016b", hexdec($element));
+ }
+ /* just save the left prefix length bits */
+ $stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
+
+ /* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
+ $stfbrokerbin = substr(sprintf("%032b", hexdec($hexbrv4)), $v4prefixlen, 32);
+ $stfbrokerbin = str_pad($stfprefixstartbin . $stfbrokerbin, 128, "0", STR_PAD_RIGHT);
+
+ /* for the local subnet too. */
+ $stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
+ $stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
+
+ /* convert the 128 bits for the broker address back into a valid IPv6 address */
+ $stfbrarr = array();
+ $stfbrbinarr = array();
+ $stfbrbinarr = str_split($stfbrokerbin, 16);
+ foreach ($stfbrbinarr as $bin) {
+ $stfbrarr[] = dechex(bindec($bin));
+ }
+ $stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
+
+ /* convert the 128 bits for the broker address back into a valid IPv6 address */
+ $stflanarr = array();
+ $stflanbinarr = array();
+ $stflanbinarr = str_split($stflanbin, 16);
+ foreach ($stflanbinarr as $bin) {
+ $stflanarr[] = dechex(bindec($bin));
+ }
+ $stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
+ $stflanarr[7] = 1;
+ $stflan = Net_IPv6::compress(implode(":", $stflanarr));
+
+ /* setup the stf interface */
+ if (!is_module_loaded("if_stf")) {
+ mwexec("/sbin/kldload if_stf.ko");
+ }
+ $stfiface = "{$interface}_stf";
+ if (does_interface_exist($stfiface)) {
+ pfSense_interface_destroy($stfiface);
+ }
+ $tmpstfiface = pfSense_interface_create("stf");
+ pfSense_interface_rename($tmpstfiface, $stfiface);
+ pfSense_interface_flags($stfiface, IFF_LINK2);
+ mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
+
+ if ($g['debug']) {
+ log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
+ }
+
+ /* write out a default router file */
+ file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
+ file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
+
+ $ip4gateway = get_interface_gateway($interface);
+ if (is_ipaddrv4($ip4gateway)) {
+ mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
+ }
+
+ if (!platform_booting()) {
+ link_interface_to_track6($interface, "update");
+ }
+
+ return 0;
+}
+
+function interface_dhcpv6_configure($interface = "wan", $wancfg) {
+ global $config, $g;
+
+ if (!is_array($wancfg)) {
+ return;
+ }
+
+ $wanif = get_real_interface($interface, "inet6");
+ $dhcp6cconf = "";
+
+ if ($wancfg['adv_dhcp6_config_file_override']) {
+ // DHCP6 Config File Override
+ $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
+ } elseif ($wancfg['adv_dhcp6_config_advanced']) {
+ // DHCP6 Config File Advanced
+ $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
+ } else {
+ // DHCP6 Config File Basic
+ $dhcp6cconf .= "interface {$wanif} {\n";
+
+ /* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
+ if ($wancfg['ipaddrv6'] == "slaac") {
+ $dhcp6cconf .= "\tinformation-only;\n";
+ $dhcp6cconf .= "\trequest domain-name-servers;\n";
+ $dhcp6cconf .= "\trequest domain-name;\n";
+ $dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
+ $dhcp6cconf .= "};\n";
+ } else {
+ $trackiflist = array();
+ $iflist = link_interface_to_track6($interface);
+ foreach ($iflist as $ifname => $ifcfg) {
+ if (is_numeric($ifcfg['track6-prefix-id'])) {
+ $trackiflist[$ifname] = $ifcfg;
+ }
+ }
+
+ /* skip address request if this is set */
+ if (!isset($wancfg['dhcp6prefixonly'])) {
+ $dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
+ }
+ if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
+ $dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
+ }
+
+ $dhcp6cconf .= "\trequest domain-name-servers;\n";
+ $dhcp6cconf .= "\trequest domain-name;\n";
+ $dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
+ $dhcp6cconf .= "};\n";
+
+ if (!isset($wancfg['dhcp6prefixonly'])) {
+ $dhcp6cconf .= "id-assoc na 0 { };\n";
+ }
+
+ if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
+ /* Setup the prefix delegation */
+ $dhcp6cconf .= "id-assoc pd 0 {\n";
+ $preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
+ if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
+ $dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
+ }
+ foreach ($trackiflist as $friendly => $ifcfg) {
+ if ($g['debug']) {
+ log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
+ }
+ $realif = get_real_interface($friendly);
+ $dhcp6cconf .= "\tprefix-interface {$realif} {\n";
+ $dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
+ $dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
+ $dhcp6cconf .= "\t};\n";
+ }
+ unset($preflen, $iflist, $ifcfg, $ifname);
+ $dhcp6cconf .= "};\n";
+ }
+ unset($trackiflist);
+ }
+ }
+
+ /* wide-dhcp6c works for now. */
+ if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
+ printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
+ unset($dhcp6cconf);
+ return 1;
+ }
+ unset($dhcp6cconf);
+
+ $dhcp6cscript = "#!/bin/sh\n";
+ $dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
+ $dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
+ $dhcp6cscript .= "dmnames=\${new_domain_name}\n";
+ $dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
+ /* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
+ if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
+ printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
+ unset($dhcp6cscript);
+ return 1;
+ }
+ unset($dhcp6cscript);
+ @chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
+
+ $rtsoldscript = "#!/bin/sh\n";
+ $rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
+ $rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
+ $rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
+ $rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
+ $rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
+ $rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
+ $rtsoldscript .= "\t/bin/sleep 1\n";
+ $rtsoldscript .= "fi\n";
+ $rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
+ $rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
+ /* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
+ if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
+ printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
+ unset($rtsoldscript);
+ return 1;
+ }
+ unset($rtsoldscript);
+ @chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
+
+ /* accept router advertisements for this interface */
+ set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
+ log_error("Accept router advertisements on interface {$wanif} ");
+ mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
+
+ /* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
+ if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
+ killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
+ sleep(2);
+ }
+ mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
+
+ /* NOTE: will be called from rtsold invoked script
+ * link_interface_to_track6($interface, "update");
+ */
+
+ return 0;
+}
+
+function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
+ global $g;
+
+ $send_options = "";
+ if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
+ $options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
+ foreach ($options as $option) {
+ $send_options .= "\tsend " . trim($option) . ";\n";
+ }
+ }
+
+ $request_options = "";
+ if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
+ $options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
+ foreach ($options as $option) {
+ $request_options .= "\trequest " . trim($option) . ";\n";
+ }
+ }
+
+ $information_only = "";
+ if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
+ $information_only = "\tinformation-only;\n";
+ }
+
+ $script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
+ if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
+ $script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
+ }
+
+ $interface_statement = "interface";
+ $interface_statement .= " {$wanif}";
+ $interface_statement .= " {\n";
+ $interface_statement .= "$send_options";
+ $interface_statement .= "$request_options";
+ $interface_statement .= "$information_only";
+ $interface_statement .= "$script";
+ $interface_statement .= "};\n";
+
+ $id_assoc_statement_address = "";
+ if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
+ $id_assoc_statement_address .= "id-assoc";
+ $id_assoc_statement_address .= " na";
+ if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
+ $id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
+ }
+ $id_assoc_statement_address .= " { ";
+
+ if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
+ (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
+ ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
+ $id_assoc_statement_address .= "\n\taddress";
+ $id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
+ $id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
+ if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
+ ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
+ $id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
+ }
+ $id_assoc_statement_address .= ";\n";
+ }
+
+ $id_assoc_statement_address .= "};\n";
+ }
+
+ $id_assoc_statement_prefix = "";
+ if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
+ $id_assoc_statement_prefix .= "id-assoc";
+ $id_assoc_statement_prefix .= " pd";
+ if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
+ $id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
+ }
+ $id_assoc_statement_prefix .= " { ";
+
+ if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
+ (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
+ ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
+ $id_assoc_statement_prefix .= "\n\tprefix";
+ $id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
+ $id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
+ if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
+ ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
+ $id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
+ }
+ $id_assoc_statement_prefix .= ";";
+ }
+
+ if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
+ $id_assoc_statement_prefix .= "\n\tprefix-interface";
+ $id_assoc_statement_prefix .= " {$wanif}";
+ $id_assoc_statement_prefix .= " {\n";
+ $id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
+ if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
+ ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
+ $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
+ }
+ $id_assoc_statement_prefix .= "\t};";
+ }
+
+ if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
+ (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
+ $id_assoc_statement_prefix .= "\n";
+ }
+
+ $id_assoc_statement_prefix .= "};\n";
+ }
+
+ $authentication_statement = "";
+ if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
+ ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
+ $authentication_statement .= "authentication";
+ $authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
+ $authentication_statement .= " {\n";
+ $authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
+ if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
+ $authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
+ }
+ if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
+ $authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
+ }
+ $authentication_statement .= "};\n";
+ }
+
+ $key_info_statement = "";
+ if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
+ ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
+ (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
+ ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
+ $key_info_statement .= "keyinfo";
+ $key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
+ $key_info_statement .= " {\n";
+ $key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
+ $key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
+ $key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
+ if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
+ $key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
+ }
+ $key_info_statement .= "};\n";
+ }
+
+ $dhcp6cconf = $interface_statement;
+ $dhcp6cconf .= $id_assoc_statement_address;
+ $dhcp6cconf .= $id_assoc_statement_prefix;
+ $dhcp6cconf .= $authentication_statement;
+ $dhcp6cconf .= $key_info_statement;
+
+ $dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
+
+ return $dhcp6cconf;
+}
+
+
+function DHCP6_Config_File_Override($wancfg, $wanif) {
+
+ $dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
+
+ if ($dhcp6cconf === false) {
+ log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
+ return '';
+ } else {
+ return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
+ }
+}
+
+
+function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
+
+ $dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
+
+ return $dhcp6cconf;
+}
+
+
+function interface_dhcp_configure($interface = "wan") {
+ global $config, $g;
+
+ $wancfg = $config['interfaces'][$interface];
+ $wanif = $wancfg['if'];
+ if (empty($wancfg)) {
+ $wancfg = array();
+ }
+
+ /* generate dhclient_wan.conf */
+ $fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
+ if (!$fd) {
+ printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
+ return 1;
+ }
+
+ if ($wancfg['dhcphostname']) {
+ $dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
+ $dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
+ } else {
+ $dhclientconf_hostname = "";
+ }
+
+ $wanif = get_real_interface($interface);
+ if (empty($wanif)) {
+ log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
+ return 0;
+ }
+ $dhclientconf = "";
+
+ $dhclientconf .= <<<EOD
+interface "{$wanif}" {
+timeout 60;
+retry 15;
+select-timeout 0;
+initial-interval 1;
+ {$dhclientconf_hostname}
+ script "/sbin/dhclient-script";
+EOD;
+
+ if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
+ $dhclientconf .= <<<EOD
+
+ reject {$wancfg['dhcprejectfrom']};
+EOD;
+ }
+ $dhclientconf .= <<<EOD
+
+}
+
+EOD;
+
+ // DHCP Config File Advanced
+ if ($wancfg['adv_dhcp_config_advanced']) {
+ $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
+ }
+
+ if (is_ipaddr($wancfg['alias-address'])) {
+ $subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
+ $dhclientconf .= <<<EOD
+alias {
+ interface "{$wanif}";
+ fixed-address {$wancfg['alias-address']};
+ option subnet-mask {$subnetmask};
+}
+
+EOD;
+ }
+
+ // DHCP Config File Override
+ if ($wancfg['adv_dhcp_config_file_override']) {
+ $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
+ }
+
+ fwrite($fd, $dhclientconf);
+ fclose($fd);
+
+ /* bring wan interface up before starting dhclient */
+ if ($wanif) {
+ interfaces_bring_up($wanif);
+ } else {
+ log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
+ }
+
+ /* Make sure dhclient is not running */
+ kill_dhclient_process($wanif);
+
+ /* fire up dhclient */
+ mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$wanif} > {$g['tmp_path']}/{$wanif}_output 2> {$g['tmp_path']}/{$wanif}_error_output");
+
+ return 0;
+}
+
+function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
+
+ $hostname = "";
+ if ($wancfg['dhcphostname'] != '') {
+ $hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
+ }
+
+ /* DHCP Protocol Timings */
+ $protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
+ foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
+ $pt_variable = "{$Protocol_Timing}";
+ ${$pt_variable} = "";
+ if ($wancfg[$Protocol_Timing] != "") {
+ ${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
+ }
+ }
+
+ $send_options = "";
+ if ($wancfg['adv_dhcp_send_options'] != '') {
+ $options = explode(',', $wancfg['adv_dhcp_send_options']);
+ foreach ($options as $option) {
+ $send_options .= "\tsend " . trim($option) . ";\n";
+ }
+ }
+
+ $request_options = "";
+ if ($wancfg['adv_dhcp_request_options'] != '') {
+ $request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
+ }
+
+ $required_options = "";
+ if ($wancfg['adv_dhcp_required_options'] != '') {
+ $required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
+ }
+
+ $option_modifiers = "";
+ if ($wancfg['adv_dhcp_option_modifiers'] != '') {
+ $modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
+ foreach ($modifiers as $modifier) {
+ $option_modifiers .= "\t" . trim($modifier) . ";\n";
+ }
+ }
+
+ $dhclientconf = "interface \"{$wanif}\" {\n";
+ $dhclientconf .= "\n";
+ $dhclientconf .= "# DHCP Protocol Timing Values\n";
+ $dhclientconf .= "{$adv_dhcp_pt_timeout}";
+ $dhclientconf .= "{$adv_dhcp_pt_retry}";
+ $dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
+ $dhclientconf .= "{$adv_dhcp_pt_reboot}";
+ $dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
+ $dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
+ $dhclientconf .= "\n";
+ $dhclientconf .= "# DHCP Protocol Options\n";
+ $dhclientconf .= "{$hostname}";
+ $dhclientconf .= "{$send_options}";
+ $dhclientconf .= "{$request_options}";
+ $dhclientconf .= "{$required_options}";
+ $dhclientconf .= "{$option_modifiers}";
+ $dhclientconf .= "\n";
+ $dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
+ $dhclientconf .= "}\n";
+
+ $dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
+
+ return $dhclientconf;
+}
+
+
+function DHCP_Config_File_Override($wancfg, $wanif) {
+
+ $dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
+
+ if ($dhclientconf === false) {
+ log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
+ return '';
+ } else {
+ return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
+ }
+}
+
+
+function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
+
+ /* Apply Interface Substitutions */
+ $dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
+
+ /* Apply Hostname Substitutions */
+ $dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
+
+ /* Arrays of MAC Address Types, Cases, Delimiters */
+ /* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
+ $various_mac_types = array("mac_addr_ascii", "mac_addr_hex");
+ $various_mac_cases = array("U", "L");
+ $various_mac_delimiters = array("", " ", ":", "-", ".");
+
+ /* Apply MAC Address Substitutions */
+ foreach ($various_mac_types as $various_mac_type) {
+ foreach ($various_mac_cases as $various_mac_case) {
+ foreach ($various_mac_delimiters as $various_mac_delimiter) {
+
+ $res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
+ if ($res !== false) {
+
+ /* Get MAC Address as ASCII String With Colon (:) delimiters */
+ if ("$various_mac_case" == "U") {
+ $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
+ }
+ if ("$various_mac_case" == "L") {
+ $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
+ }
+
+ if ("$various_mac_type" == "mac_addr_hex") {
+ /* Convert MAC ascii string to HEX with colon (:) delimiters. */
+ $dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
+ $dhcpclientconf_mac_hex = "";
+ $delimiter = "";
+ for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
+ $dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
+ $delimiter = ":";
+ }
+ $dhcpclientconf_mac = $dhcpclientconf_mac_hex;
+ }
+
+ /* MAC Address Delimiter Substitutions */
+ $dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
+
+ /* Apply MAC Address Substitutions */
+ $dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
+ }
+ }
+ }
+ }
+
+ return $dhclientconf;
+}
+
+function interfaces_group_setup() {
+ global $config;
+
+ if (!is_array($config['ifgroups']['ifgroupentry'])) {
+ return;
+ }
+
+ foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
+ interface_group_setup($groupar);
+ }
+
+ return;
+}
+
+function interface_group_setup(&$groupname /* The parameter is an array */) {
+ global $config;
+
+ if (!is_array($groupname)) {
+ return;
+ }
+ $members = explode(" ", $groupname['members']);
+ foreach ($members as $ifs) {
+ $realif = get_real_interface($ifs);
+ if ($realif && does_interface_exist($realif)) {
+ mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
+ }
+ }
+
+ return;
+}
+
+function is_interface_group($if) {
+ global $config;
+
+ if (is_array($config['ifgroups']['ifgroupentry'])) {
+ foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
+ if ($groupentry['ifname'] === $if) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function interface_group_add_member($interface, $groupname) {
+ $interface = get_real_interface($interface);
+ if (does_interface_exist($interface)) {
+ mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
+ }
+}
+
+/* COMPAT Function */
+function convert_friendly_interface_to_real_interface_name($interface) {
+ return get_real_interface($interface);
+}
+
+/* COMPAT Function */
+function get_real_wan_interface($interface = "wan") {
+ return get_real_interface($interface);
+}
+
+/* COMPAT Function */
+function get_current_wan_address($interface = "wan") {
+ return get_interface_ip($interface);
+}
+
+/*
+ * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
+ */
+function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
+ global $config;
+
+ if (stripos($interface, "_vip")) {
+ foreach ($config['virtualip']['vip'] as $counter => $vip) {
+ if ($vip['mode'] == "carp") {
+ if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
+ return $vip['interface'];
+ }
+ }
+ }
+ }
+
+ /* XXX: For speed reasons reference directly the interface array */
+ $ifdescrs = &$config['interfaces'];
+ //$ifdescrs = get_configured_interface_list(false, true);
+
+ foreach ($ifdescrs as $if => $ifname) {
+ if ($if == $interface || $ifname['if'] == $interface) {
+ return $if;
+ }
+
+ if (get_real_interface($if) == $interface) {
+ return $if;
+ }
+
+ if ($checkparent == false) {
+ continue;
+ }
+
+ $int = get_parent_interface($if, true);
+ if (is_array($int)) {
+ foreach ($int as $iface) {
+ if ($iface == $interface) {
+ return $if;
+ }
+ }
+ }
+ }
+
+ if ($interface == "enc0") {
+ return 'IPsec';
+ }
+}
+
+/* attempt to resolve interface to friendly descr */
+function convert_friendly_interface_to_friendly_descr($interface) {
+ global $config;
+
+ switch ($interface) {
+ case "l2tp":
+ $ifdesc = "L2TP";
+ break;
+ case "pptp":
+ $ifdesc = "PPTP";
+ break;
+ case "pppoe":
+ $ifdesc = "PPPoE";
+ break;
+ case "openvpn":
+ $ifdesc = "OpenVPN";
+ break;
+ case "enc0":
+ case "ipsec":
+ case "IPsec":
+ $ifdesc = "IPsec";
+ break;
+ default:
+ if (isset($config['interfaces'][$interface])) {
+ if (empty($config['interfaces'][$interface]['descr'])) {
+ $ifdesc = strtoupper($interface);
+ } else {
+ $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
+ }
+ break;
+ } else if (substr($interface, 0, 4) == '_vip') {
+ if (is_array($config['virtualip']['vip'])) {
+ foreach ($config['virtualip']['vip'] as $counter => $vip) {
+ if ($vip['mode'] == "carp") {
+ if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
+ return "{$vip['subnet']} - {$vip['descr']}";
+ }
+ }
+ }
+ }
+ } else if (substr($interface, 0, 5) == '_lloc') {
+ return get_interface_linklocal($interface);
+ } else {
+ /* if list */
+ $ifdescrs = get_configured_interface_with_descr(false, true);
+ foreach ($ifdescrs as $if => $ifname) {
+ if ($if == $interface || $ifname == $interface) {
+ return $ifname;
+ }
+ }
+ }
+ break;
+ }
+
+ return $ifdesc;
+}
+
+function convert_real_interface_to_friendly_descr($interface) {
+
+ $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
+
+ if (!empty($ifdesc)) {
+ return convert_friendly_interface_to_friendly_descr($ifdesc);
+ }
+
+ return $interface;
+}
+
+/*
+ * get_parent_interface($interface):
+ * --returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
+ * or virtual interface (i.e. vlan)
+ * (We need array because MLPPP and bridge interfaces have more than one parent.)
+ * -- returns $interface passed in if $interface parent is not found
+ * -- returns empty array if an invalid interface is passed
+ * (Only handles ppps and vlans now.)
+ */
+function get_parent_interface($interface, $avoidrecurse = false) {
+ global $config;
+
+ $parents = array();
+ //Check that we got a valid interface passed
+ $realif = get_real_interface($interface);
+ if ($realif == NULL) {
+ return $parents;
+ }
+
+ // If we got a real interface, find it's friendly assigned name
+ if ($interface == $realif && $avoidrecurse == false) {
+ $interface = convert_real_interface_to_friendly_interface_name($interface);
+ }
+
+ if (!empty($interface) && isset($config['interfaces'][$interface])) {
+ $ifcfg = $config['interfaces'][$interface];
+ switch ($ifcfg['ipaddr']) {
+ case "ppp":
+ case "pppoe":
+ case "pptp":
+ case "l2tp":
+ if (empty($parents)) {
+ if (is_array($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
+ if ($ifcfg['if'] == $ppp['if']) {
+ $ports = explode(',', $ppp['ports']);
+ foreach ($ports as $pid => $parent_if) {
+ $parents[$pid] = get_real_interface($parent_if);
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case "dhcp":
+ case "static":
+ default:
+ // Handle _vlans
+ if (strpos($realif, '_vlan') !== FALSE) {
+ if (is_array($config['vlans']['vlan'])) {
+ foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
+ if ($ifcfg['if'] == $vlan['vlanif']) {
+ $parents[0] = $vlan['if'];
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (empty($parents)) {
+ $parents[0] = $realif;
+ }
+
+ return $parents;
+}
+
+function interface_is_wireless_clone($wlif) {
+ if (!stristr($wlif, "_wlan")) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+function interface_get_wireless_base($wlif) {
+ if (!stristr($wlif, "_wlan")) {
+ return $wlif;
+ } else {
+ return substr($wlif, 0, stripos($wlif, "_wlan"));
+ }
+}
+
+function interface_get_wireless_clone($wlif) {
+ if (!stristr($wlif, "_wlan")) {
+ return $wlif . "_wlan0";
+ } else {
+ return $wlif;
+ }
+}
+
+function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
+ global $config, $g;
+
+ $wanif = NULL;
+
+ switch ($interface) {
+ case "l2tp":
+ $wanif = "l2tp";
+ break;
+ case "pptp":
+ $wanif = "pptp";
+ break;
+ case "pppoe":
+ $wanif = "pppoe";
+ break;
+ case "openvpn":
+ $wanif = "openvpn";
+ break;
+ case "ipsec":
+ case "enc0":
+ $wanif = "enc0";
+ break;
+ case "ppp":
+ $wanif = "ppp";
+ break;
+ default:
+ if (substr($interface, 0, 4) == '_vip') {
+ $wanif = get_configured_carp_interface_list($interface, '', 'iface');
+ if (!empty($wanif)) {
+ $wanif = get_real_interface($wanif, $family);
+ }
+ break;
+ } else if (substr($interface, 0, 5) == '_lloc') {
+ $interface = substr($interface, 5);
+ } else if (does_interface_exist($interface, $flush)) {
+ /*
+ * If a real interface was already passed simply
+ * pass the real interface back. This encourages
+ * the usage of this function in more cases so that
+ * we can combine logic for more flexibility.
+ */
+ $wanif = $interface;
+ break;
+ }
+
+ if (empty($config['interfaces'][$interface])) {
+ break;
+ }
+
+ $cfg = &$config['interfaces'][$interface];
+
+ if ($family == "inet6") {
+ switch ($cfg['ipaddrv6']) {
+ case "6rd":
+ case "6to4":
+ $wanif = "{$interface}_stf";
+ break;
+ case 'pppoe':
+ case 'ppp':
+ case 'l2tp':
+ case 'pptp':
+ if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
+ $wanif = interface_get_wireless_clone($cfg['if']);
+ } else {
+ $wanif = $cfg['if'];
+ }
+ break;
+ default:
+ switch ($cfg['ipaddr']) {
+ case 'pppoe':
+ case 'ppp':
+ case 'l2tp':
+ case 'pptp':
+ if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
+ $wanif = $cfg['if'];
+ } else {
+ $parents = get_parent_interface($interface);
+ if (!empty($parents[0])) {
+ $wanif = $parents[0];
+ } else {
+ $wanif = $cfg['if'];
+ }
+ }
+ break;
+ default:
+ if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
+ $wanif = interface_get_wireless_clone($cfg['if']);
+ } else {
+ $wanif = $cfg['if'];
+ }
+ break;
+ }
+ break;
+ }
+ } else {
+ // Wireless cloned NIC support (FreeBSD 8+)
+ // interface name format: $parentnic_wlanparentnic#
+ // example: ath0_wlan0
+ if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
+ $wanif = interface_get_wireless_clone($cfg['if']);
+ } else {
+ $wanif = $cfg['if'];
+ }
+ }
+ break;
+ }
+
+ return $wanif;
+}
+
+/* Guess the physical interface by providing a IP address */
+function guess_interface_from_ip($ipaddress) {
+
+ $family = '';
+ if (is_ipaddrv4($ipaddress)) {
+ $family = 'inet';
+ }
+ if (empty($family) && is_ipaddrv6($ipaddress)) {
+ $family = 'inet6';
+ }
+
+ if (empty($family)) {
+ return false;
+ }
+
+ /* create a route table we can search */
+ $output = '';
+ $_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
+ $output[0] = trim($output[0], " \n");
+ if (!empty($output[0])) {
+ return $output[0];
+ }
+
+ return false;
+}
+
+/*
+ * find_ip_interface($ip): return the interface where an ip is defined
+ * (or if $bits is specified, where an IP within the subnet is defined)
+ */
+function find_ip_interface($ip, $bits = null) {
+ if (!is_ipaddr($ip)) {
+ return false;
+ }
+
+ $isv6ip = is_ipaddrv6($ip);
+
+ /* if list */
+ $ifdescrs = get_configured_interface_list();
+
+ foreach ($ifdescrs as $ifdescr => $ifname) {
+ $ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
+ if (is_null($ifip)) {
+ continue;
+ }
+ if (is_null($bits)) {
+ if ($ip == $ifip) {
+ $int = get_real_interface($ifname);
+ return $int;
+ }
+ } else {
+ if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
+ $int = get_real_interface($ifname);
+ return $int;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
+ * (or if $bits is specified, where an IP within the subnet is found)
+ */
+function find_virtual_ip_alias($ip, $bits = null) {
+ global $config;
+
+ if (!is_array($config['virtualip']['vip'])) {
+ return false;
+ }
+ if (!is_ipaddr($ip)) {
+ return false;
+ }
+
+ $isv6ip = is_ipaddrv6($ip);
+
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['mode'] === "ipalias") {
+ if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
+ continue;
+ }
+ if (is_null($bits)) {
+ if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
+ return $vip;
+ }
+ } else {
+ if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
+ (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
+ return $vip;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * find_number_of_created_carp_interfaces: return the number of carp interfaces
+ */
+function find_number_of_created_carp_interfaces() {
+ return `/sbin/ifconfig | grep "carp:" | wc -l`;
+}
+
+/*
+ * find_carp_interface($ip): return the carp interface where an ip is defined
+ */
+function find_carp_interface($ip) {
+ global $config;
+ if (is_array($config['virtualip']['vip'])) {
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['mode'] == "carp") {
+ if (is_ipaddrv4($ip)) {
+ $carp_ip = get_interface_ip($vip['interface']);
+ }
+ if (is_ipaddrv6($ip)) {
+ $carp_ip = get_interface_ipv6($vip['interface']);
+ }
+ exec("/sbin/ifconfig", $output, $return);
+ foreach ($output as $line) {
+ $elements = preg_split("/[ ]+/i", $line);
+ if (strstr($elements[0], "vip")) {
+ $curif = str_replace(":", "", $elements[0]);
+ }
+ if (stristr($line, $ip)) {
+ $if = $curif;
+ continue;
+ }
+ }
+
+ if ($if) {
+ return $if;
+ }
+ }
+ }
+ }
+}
+
+function link_carp_interface_to_parent($interface) {
+ global $config;
+
+ if (empty($interface)) {
+ return;
+ }
+
+ $carp_ip = get_interface_ip($interface);
+ $carp_ipv6 = get_interface_ipv6($interface);
+
+ if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
+ return;
+ }
+
+ /* if list */
+ $ifdescrs = get_configured_interface_list();
+ foreach ($ifdescrs as $ifdescr => $ifname) {
+ /* check IPv4 */
+ if (is_ipaddrv4($carp_ip)) {
+ $interfaceip = get_interface_ip($ifname);
+ $subnet_bits = get_interface_subnet($ifname);
+ $subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
+ if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
+ return $ifname;
+ }
+ }
+ /* Check IPv6 */
+ if (is_ipaddrv6($carp_ipv6)) {
+ $interfaceipv6 = get_interface_ipv6($ifname);
+ $prefixlen = get_interface_subnetv6($ifname);
+ if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
+ return $ifname;
+ }
+ }
+ }
+ return "";
+}
+
+
+/****f* interfaces/link_ip_to_carp_interface
+ * NAME
+ * link_ip_to_carp_interface - Find where a CARP interface links to.
+ * INPUTS
+ * $ip
+ * RESULT
+ * $carp_ints
+ ******/
+function link_ip_to_carp_interface($ip) {
+ global $config;
+
+ if (!is_ipaddr($ip)) {
+ return;
+ }
+
+ $carp_ints = "";
+ if (is_array($config['virtualip']['vip'])) {
+ $first = 0;
+ $carp_int = array();
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['mode'] == "carp") {
+ $carp_ip = $vip['subnet'];
+ $carp_sn = $vip['subnet_bits'];
+ $carp_nw = gen_subnet($carp_ip, $carp_sn);
+ if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
+ $carp_int[] = get_real_interface($vip['interface']);
+ }
+ }
+ }
+ if (!empty($carp_int)) {
+ $carp_ints = implode(" ", array_unique($carp_int));
+ }
+ }
+
+ return $carp_ints;
+}
+
+function link_interface_to_track6($int, $action = "") {
+ global $config;
+
+ if (empty($int)) {
+ return;
+ }
+
+ if (is_array($config['interfaces'])) {
+ $list = array();
+ foreach ($config['interfaces'] as $ifname => $ifcfg) {
+ if (!isset($ifcfg['enable'])) {
+ continue;
+ }
+ if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
+ if ($action == "update") {
+ interface_track6_configure($ifname, $ifcfg);
+ } else if ($action == "") {
+ $list[$ifname] = $ifcfg;
+ }
+ }
+ }
+ return $list;
+ }
+}
+
+function interface_find_child_cfgmtu($realiface) {
+ global $config;
+
+ $interface = convert_real_interface_to_friendly_interface_name($realiface);
+ $vlans = link_interface_to_vlans($realiface);
+ $bridge = link_interface_to_bridge($realiface);
+ if (!empty($interface)) {
+ $gifs = link_interface_to_gif($interface);
+ $gres = link_interface_to_gre($interface);
+ } else {
+ $gifs = array();
+ $gres = array();
+ }
+
+ $mtu = 0;
+ if (is_array($vlans)) {
+ foreach ($vlans as $vlan) {
+ $ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
+ if (empty($ifass)) {
+ continue;
+ }
+ if (!empty($config['interfaces'][$ifass]['mtu'])) {
+ if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
+ $mtu = intval($config['interfaces'][$ifass]['mtu']);
+ }
+ }
+ }
+ }
+ if (is_array($gifs)) {
+ foreach ($gifs as $vlan) {
+ $ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
+ if (empty($ifass)) {
+ continue;
+ }
+ if (!empty($config['interfaces'][$ifass]['mtu'])) {
+ if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
+ $mtu = intval($config['interfaces'][$ifass]['mtu']);
+ }
+ }
+ }
+ }
+ if (is_array($gres)) {
+ foreach ($gres as $vlan) {
+ $ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
+ if (empty($ifass)) {
+ continue;
+ }
+ if (!empty($config['interfaces'][$ifass]['mtu'])) {
+ if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
+ $mtu = intval($config['interfaces'][$ifass]['mtu']);
+ }
+ }
+ }
+ }
+ $ifass = convert_real_interface_to_friendly_interface_name($bridge);
+ if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
+ if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
+ $mtu = intval($config['interfaces'][$ifass]['mtu']);
+ }
+ }
+ unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
+
+ return $mtu;
+}
+
+function link_interface_to_vlans($int, $action = "") {
+ global $config;
+
+ if (empty($int)) {
+ return;
+ }
+
+ if (is_array($config['vlans']['vlan'])) {
+ $ifaces = array();
+ foreach ($config['vlans']['vlan'] as $vlan) {
+ if ($int == $vlan['if']) {
+ if ($action == "update") {
+ interfaces_bring_up($int);
+ } else {
+ $ifaces[$vlan['tag']] = $vlan;
+ }
+ }
+ }
+ if (!empty($ifaces)) {
+ return $ifaces;
+ }
+ }
+}
+
+function link_interface_to_vips($int, $action = "", $vhid = '') {
+ global $config;
+
+ if (is_array($config['virtualip']['vip'])) {
+ $result = array();
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($int == $vip['interface']) {
+ if ($action == "update") {
+ interfaces_vips_configure($int);
+ } else {
+ if (empty($vhid) || ($vhid == $vip['vhid'])) {
+ $result[] = $vip;
+ }
+ }
+ }
+ }
+ return $result;
+ }
+}
+
+/****f* interfaces/link_interface_to_bridge
+ * NAME
+ * link_interface_to_bridge - Finds out a bridge group for an interface
+ * INPUTS
+ * $ip
+ * RESULT
+ * bridge[0-99]
+ ******/
+function link_interface_to_bridge($int) {
+ global $config;
+
+ if (is_array($config['bridges']['bridged'])) {
+ foreach ($config['bridges']['bridged'] as $bridge) {
+ if (in_array($int, explode(',', $bridge['members']))) {
+ return "{$bridge['bridgeif']}";
+ }
+ }
+ }
+}
+
+function link_interface_to_group($int) {
+ global $config;
+
+ $result = array();
+
+ if (is_array($config['ifgroups']['ifgroupentry'])) {
+ foreach ($config['ifgroups']['ifgroupentry'] as $group) {
+ if (in_array($int, explode(" ", $group['members']))) {
+ $result[$group['ifname']] = $int;
+ }
+ }
+ }
+
+ return $result;
+}
+
+function link_interface_to_gre($interface) {
+ global $config;
+
+ $result = array();
+
+ if (is_array($config['gres']['gre'])) {
+ foreach ($config['gres']['gre'] as $gre) {
+ if ($gre['if'] == $interface) {
+ $result[] = $gre;
+ }
+ }
+ }
+
+ return $result;
+}
+
+function link_interface_to_gif($interface) {
+ global $config;
+
+ $result = array();
+
+ if (is_array($config['gifs']['gif'])) {
+ foreach ($config['gifs']['gif'] as $gif) {
+ if ($gif['if'] == $interface) {
+ $result[] = $gif;
+ }
+ }
+ }
+
+ return $result;
+}
+
+/*
+ * find_interface_ip($interface): return the interface ip (first found)
+ */
+function find_interface_ip($interface, $flush = false) {
+ global $interface_ip_arr_cache;
+ global $interface_sn_arr_cache;
+
+ $interface = str_replace("\n", "", $interface);
+
+ if (!does_interface_exist($interface)) {
+ return;
+ }
+
+ /* Setup IP cache */
+ if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
+ $ifinfo = pfSense_get_interface_addresses($interface);
+ $interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
+ $interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
+ }
+
+ return $interface_ip_arr_cache[$interface];
+}
+
+/*
+ * find_interface_ipv6($interface): return the interface ip (first found)
+ */
+function find_interface_ipv6($interface, $flush = false) {
+ global $interface_ipv6_arr_cache;
+ global $interface_snv6_arr_cache;
+ global $config;
+
+ $interface = trim($interface);
+ $interface = get_real_interface($interface);
+
+ if (!does_interface_exist($interface)) {
+ return;
+ }
+
+ /* Setup IP cache */
+ if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
+ $ifinfo = pfSense_get_interface_addresses($interface);
+ $interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
+ $interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
+ }
+
+ return $interface_ipv6_arr_cache[$interface];
+}
+
+/*
+ * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
+ */
+function find_interface_ipv6_ll($interface, $flush = false) {
+ global $interface_llv6_arr_cache;
+ global $config;
+
+ $interface = str_replace("\n", "", $interface);
+
+ if (!does_interface_exist($interface)) {
+ return;
+ }
+
+ /* Setup IP cache */
+ if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
+ $ifinfo = pfSense_getall_interface_addresses($interface);
+ foreach ($ifinfo as $line) {
+ if (strstr($line, ":")) {
+ $parts = explode("/", $line);
+ if (is_linklocal($parts[0])) {
+ $ifinfo['linklocal'] = $parts[0];
+ }
+ }
+ }
+ $interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
+ }
+ return $interface_llv6_arr_cache[$interface];
+}
+
+function find_interface_subnet($interface, $flush = false) {
+ global $interface_sn_arr_cache;
+ global $interface_ip_arr_cache;
+
+ $interface = str_replace("\n", "", $interface);
+ if (does_interface_exist($interface) == false) {
+ return;
+ }
+
+ if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
+ $ifinfo = pfSense_get_interface_addresses($interface);
+ $interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
+ $interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
+ }
+
+ return $interface_sn_arr_cache[$interface];
+}
+
+function find_interface_subnetv6($interface, $flush = false) {
+ global $interface_snv6_arr_cache;
+ global $interface_ipv6_arr_cache;
+
+ $interface = str_replace("\n", "", $interface);
+ if (does_interface_exist($interface) == false) {
+ return;
+ }
+
+ if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
+ $ifinfo = pfSense_get_interface_addresses($interface);
+ $interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
+ $interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
+ }
+
+ return $interface_snv6_arr_cache[$interface];
+}
+
+function ip_in_interface_alias_subnet($interface, $ipalias) {
+ global $config;
+
+ if (empty($interface) || !is_ipaddr($ipalias)) {
+ return false;
+ }
+ if (is_array($config['virtualip']['vip'])) {
+ foreach ($config['virtualip']['vip'] as $vip) {
+ switch ($vip['mode']) {
+ case "ipalias":
+ if ($vip['interface'] <> $interface) {
+ break;
+ }
+ $subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
+ if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+function get_possible_listen_ips($include_ipv6_link_local=false) {
+
+ $interfaces = get_configured_interface_with_descr();
+ foreach ($interfaces as $iface => $ifacename) {
+ if ($include_ipv6_link_local) {
+ /* This is to avoid going though added ll below */
+ if (substr($iface, 0, 5) == '_lloc') {
+ continue;
+ }
+ $llip = find_interface_ipv6_ll(get_real_interface($iface));
+ if (!empty($llip)) {
+ $interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
+ }
+ }
+ }
+ /* XXX: Maybe use array_merge below? */
+ $carplist = get_configured_carp_interface_list();
+ foreach ($carplist as $cif => $carpip) {
+ $interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
+ }
+ $aliaslist = get_configured_ip_aliases_list();
+ foreach ($aliaslist as $aliasip => $aliasif) {
+ $interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
+ }
+
+ $interfaces['lo0'] = 'Localhost';
+
+ return $interfaces;
+}
+
+function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
+ global $config;
+
+ $sourceips = get_possible_listen_ips($include_ipv6_link_local);
+ foreach (array('server', 'client') as $mode) {
+ if (is_array($config['openvpn']["openvpn-{$mode}"])) {
+ foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
+ if (!isset($setting['disable'])) {
+ $sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
+ $sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
+ }
+ }
+ }
+ }
+ return $sourceips;
+}
+
+function get_interface_ip($interface = "wan") {
+
+ $realif = get_failover_interface($interface);
+ if (!$realif) {
+ return null;
+ }
+
+ if (substr($realif, 0, 4) == '_vip') {
+ return get_configured_carp_interface_list($realif, 'inet', 'ip');
+ }
+
+ if (strstr($realif, "_vip")) {
+ return get_configured_carp_interface_list($realif);
+ }
+
+ $curip = find_interface_ip($realif);
+ if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
+ return $curip;
+ } else {
+ return null;
+ }
+}
+
+function get_interface_ipv6($interface = "wan", $flush = false) {
+ global $config;
+
+ $realif = get_failover_interface($interface, 'inet6');
+ if (!$realif) {
+ return null;
+ }
+
+ if (substr($realif, 0, 4) == '_vip') {
+ return get_configured_carp_interface_list($realif, 'inet6', 'ip');
+ } else if (substr($realif, 0, 5) == '_lloc') {
+ return get_interface_linklocal($interface);
+ }
+
+ if (is_array($config['interfaces'][$interface])) {
+ switch ($config['interfaces'][$interface]['ipaddr']) {
+ case 'pppoe':
+ case 'l2tp':
+ case 'pptp':
+ case 'ppp':
+ if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
+ $realif = get_real_interface($interface, 'inet6', true);
+ }
+ break;
+ }
+ }
+
+ $curip = find_interface_ipv6($realif, $flush);
+ if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
+ return $curip;
+ } else {
+ /*
+ * NOTE: On the case when only the prefix is requested,
+ * the communication on WAN will be done over link-local.
+ */
+ if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
+ $curip = find_interface_ipv6_ll($realif, $flush);
+ if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
+ return $curip;
+ }
+ }
+ }
+ return null;
+}
+
+function get_interface_linklocal($interface = "wan") {
+
+ $realif = get_failover_interface($interface, 'inet6');
+ if (!$realif) {
+ return null;
+ }
+
+ if (substr($interface, 0, 4) == '_vip') {
+ $realif = get_real_interface($interface);
+ } else if (substr($interface, 0, 5) == '_lloc') {
+ $realif = get_real_interface(substr($interface, 5));
+ }
+
+ $curip = find_interface_ipv6_ll($realif);
+ if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
+ return $curip;
+ } else {
+ return null;
+ }
+}
+
+function get_interface_subnet($interface = "wan") {
+
+ if (substr($interface, 0, 4) == '_vip') {
+ return get_configured_carp_interface_list($interface, 'inet', 'subnet');
+ }
+
+ $realif = get_real_interface($interface);
+ if (!$realif) {
+ return null;
+ }
+
+ $cursn = find_interface_subnet($realif);
+ if (!empty($cursn)) {
+ return $cursn;
+ }
+
+ return null;
+}
+
+function get_interface_subnetv6($interface = "wan") {
+
+ if (substr($interface, 0, 4) == '_vip') {
+ return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
+ } else if (substr($interface, 0, 5) == '_lloc') {
+ $interface = substr($interface, 5);
+ }
+
+ $realif = get_real_interface($interface, 'inet6');
+ if (!$realif) {
+ return null;
+ }
+
+ $cursn = find_interface_subnetv6($realif);
+ if (!empty($cursn)) {
+ return $cursn;
+ }
+
+ return null;
+}
+
+/* return outside interfaces with a gateway */
+function get_interfaces_with_gateway() {
+ global $config;
+
+ $ints = array();
+
+ /* loop interfaces, check config for outbound */
+ foreach ($config['interfaces'] as $ifdescr => $ifname) {
+ switch ($ifname['ipaddr']) {
+ case "dhcp":
+ case "pppoe":
+ case "pptp":
+ case "l2tp":
+ case "ppp":
+ $ints[$ifdescr] = $ifdescr;
+ break;
+ default:
+ if (substr($ifname['if'], 0, 4) == "ovpn" ||
+ !empty($ifname['gateway'])) {
+ $ints[$ifdescr] = $ifdescr;
+ }
+ break;
+ }
+ }
+ return $ints;
+}
+
+/* return true if interface has a gateway */
+function interface_has_gateway($friendly) {
+ global $config;
+
+ if (!empty($config['interfaces'][$friendly])) {
+ $ifname = &$config['interfaces'][$friendly];
+ switch ($ifname['ipaddr']) {
+ case "dhcp":
+ case "pppoe":
+ case "pptp":
+ case "l2tp":
+ case "ppp":
+ return true;
+ break;
+ default:
+ if (substr($ifname['if'], 0, 4) == "ovpn") {
+ return true;
+ }
+ $tunnelif = substr($ifname['if'], 0, 3);
+ if ($tunnelif == "gif" || $tunnelif == "gre") {
+ return true;
+ }
+ if (!empty($ifname['gateway'])) {
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+/* return true if interface has a gateway */
+function interface_has_gatewayv6($friendly) {
+ global $config;
+
+ if (!empty($config['interfaces'][$friendly])) {
+ $ifname = &$config['interfaces'][$friendly];
+ switch ($ifname['ipaddrv6']) {
+ case "slaac":
+ case "dhcp6":
+ case "6to4":
+ case "6rd":
+ return true;
+ break;
+ default:
+ if (substr($ifname['if'], 0, 4) == "ovpn") {
+ return true;
+ }
+ $tunnelif = substr($ifname['if'], 0, 3);
+ if ($tunnelif == "gif" || $tunnelif == "gre") {
+ return true;
+ }
+ if (!empty($ifname['gatewayv6'])) {
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+/****f* interfaces/is_altq_capable
+ * NAME
+ * is_altq_capable - Test if interface is capable of using ALTQ
+ * INPUTS
+ * $int - string containing interface name
+ * RESULT
+ * boolean - true or false
+ ******/
+
+function is_altq_capable($int) {
+ /* Per:
+ * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html
+ * Only the following drivers have ALTQ support
+ * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
+ */
+ $capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
+ "bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "epair", "et", "fxp", "gem",
+ "hme", "hn", "igb", "ixgbe", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
+ "nge", "npe", "nve", "re", "rl", "sf", "sge", "sis", "sk",
+ "ste", "stge", "ti", "txp", "udav", "ural", "vge", "vmx", "vr", "vte", "xl",
+ "ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
+ "l2tp", "ppp", "vtnet");
+
+ $int_family = remove_ifindex($int);
+
+ if (in_array($int_family, $capable)) {
+ return true;
+ } else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
+ return true;
+ } else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
+ return true;
+ } else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/****f* interfaces/is_interface_wireless
+ * NAME
+ * is_interface_wireless - Returns if an interface is wireless
+ * RESULT
+ * $tmp - Returns if an interface is wireless
+ ******/
+function is_interface_wireless($interface) {
+ global $config, $g;
+
+ $friendly = convert_real_interface_to_friendly_interface_name($interface);
+ if (!isset($config['interfaces'][$friendly]['wireless'])) {
+ if (preg_match($g['wireless_regex'], $interface)) {
+ if (isset($config['interfaces'][$friendly])) {
+ $config['interfaces'][$friendly]['wireless'] = array();
+ }
+ return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
+}
+
+function get_wireless_modes($interface) {
+ /* return wireless modes and channels */
+ $wireless_modes = array();
+
+ $cloned_interface = get_real_interface($interface);
+
+ if ($cloned_interface && is_interface_wireless($cloned_interface)) {
+ $chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
+ $stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
+ $format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
+
+ $interface_channels = "";
+ exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
+ $interface_channel_count = count($interface_channels);
+
+ $c = 0;
+ while ($c < $interface_channel_count) {
+ $channel_line = explode(",", $interface_channels["$c"]);
+ $wireless_mode = trim($channel_line[0]);
+ $wireless_channel = trim($channel_line[1]);
+ if (trim($wireless_mode) != "") {
+ /* if we only have 11g also set 11b channels */
+ if ($wireless_mode == "11g") {
+ if (!isset($wireless_modes["11b"])) {
+ $wireless_modes["11b"] = array();
+ }
+ } else if ($wireless_mode == "11g ht") {
+ if (!isset($wireless_modes["11b"])) {
+ $wireless_modes["11b"] = array();
+ }
+ if (!isset($wireless_modes["11g"])) {
+ $wireless_modes["11g"] = array();
+ }
+ $wireless_mode = "11ng";
+ } else if ($wireless_mode == "11a ht") {
+ if (!isset($wireless_modes["11a"])) {
+ $wireless_modes["11a"] = array();
+ }
+ $wireless_mode = "11na";
+ }
+ $wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
+ }
+ $c++;
+ }
+ }
+ return($wireless_modes);
+}
+
+/* return channel numbers, frequency, max txpower, and max regulation txpower */
+function get_wireless_channel_info($interface) {
+ $wireless_channels = array();
+
+ $cloned_interface = get_real_interface($interface);
+
+ if ($cloned_interface && is_interface_wireless($cloned_interface)) {
+ $chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
+ $stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
+ $format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
+
+ $interface_channels = "";
+ exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
+
+ foreach ($interface_channels as $channel_line) {
+ $channel_line = explode(",", $channel_line);
+ if (!isset($wireless_channels[$channel_line[0]])) {
+ $wireless_channels[$channel_line[0]] = $channel_line;
+ }
+ }
+ }
+ return($wireless_channels);
+}
+
+/****f* interfaces/get_interface_mtu
+ * NAME
+ * get_interface_mtu - Return the mtu of an interface
+ * RESULT
+ * $tmp - Returns the mtu of an interface
+ ******/
+function get_interface_mtu($interface) {
+ $mtu = pfSense_interface_getmtu($interface);
+ return $mtu['mtu'];
+}
+
+function get_interface_mac($interface) {
+
+ $macinfo = pfSense_get_interface_addresses($interface);
+ return $macinfo["macaddr"];
+}
+
+/****f* pfsense-utils/generate_random_mac_address
+ * NAME
+ * generate_random_mac - generates a random mac address
+ * INPUTS
+ * none
+ * RESULT
+ * $mac - a random mac address
+ ******/
+function generate_random_mac_address() {
+ $mac = "02";
+ for ($x = 0; $x < 5; $x++) {
+ $mac .= ":" . dechex(rand(16, 255));
+ }
+ return $mac;
+}
+
+/****f* interfaces/is_jumbo_capable
+ * NAME
+ * is_jumbo_capable - Test if interface is jumbo frame capable. Useful for determining VLAN capability.
+ * INPUTS
+ * $int - string containing interface name
+ * RESULT
+ * boolean - true or false
+ ******/
+function is_jumbo_capable($iface) {
+ $iface = trim($iface);
+ $capable = pfSense_get_interface_addresses($iface);
+
+ if (isset($capable['caps']['vlanmtu'])) {
+ return true;
+ }
+
+ // hack for some lagg modes missing vlanmtu, but work fine w/VLANs
+ if (substr($iface, 0, 4) == "lagg") {
+ return true;
+ }
+
+ return false;
+}
+
+function interface_setup_pppoe_reset_file($pppif, $iface="") {
+ global $g;
+
+ $cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
+
+ if (!empty($iface) && !empty($pppif)) {
+ $cron_cmd = <<<EOD
+#!/bin/sh
+/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
+/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
+
+EOD;
+
+ @file_put_contents($cron_file, $cron_cmd);
+ chmod($cron_file, 0755);
+ sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
+ } else {
+ unlink_if_exists($cron_file);
+ }
+}
+
+function get_interface_default_mtu($type = "ethernet") {
+ switch ($type) {
+ case "gre":
+ return 1476;
+ break;
+ case "gif":
+ return 1280;
+ break;
+ case "tun":
+ case "vlan":
+ case "tap":
+ case "ethernet":
+ default:
+ return 1500;
+ break;
+ }
+
+ /* Never reached */
+ return 1500;
+}
+
+function get_vip_descr($ipaddress) {
+ global $config;
+
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['subnet'] == $ipaddress) {
+ return ($vip['descr']);
+ }
+ }
+ return "";
+}
+
+function interfaces_staticarp_configure($if) {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "interfaces_staticarp_configure($if) being called $mt\n";
+ }
+
+ $ifcfg = $config['interfaces'][$if];
+
+ if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
+ return 0;
+ }
+
+ /* Enable staticarp, if enabled */
+ if (isset($config['dhcpd'][$if]['staticarp'])) {
+ mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
+ mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
+ if (is_array($config['dhcpd'][$if]['staticmap'])) {
+ foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
+ mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
+ }
+ }
+ } else {
+ mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
+ mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
+ if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
+ foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
+ if (isset($arpent['arp_table_static_entry'])) {
+ mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+function get_failover_interface($interface, $family = "all") {
+ global $config;
+
+ /* shortcut to get_real_interface if we find it in the config */
+ if (is_array($config['interfaces'][$interface])) {
+ return get_real_interface($interface, $family);
+ }
+
+ /* compare against gateway groups */
+ $a_groups = return_gateway_groups_array();
+ if (is_array($a_groups[$interface])) {
+ /* we found a gateway group, fetch the interface or vip */
+ if (!empty($a_groups[$interface][0]['vip'])) {
+ return $a_groups[$interface][0]['vip'];
+ } else {
+ return $a_groups[$interface][0]['int'];
+ }
+ }
+ /* fall through to get_real_interface */
+ /* XXX: Really needed? */
+ return get_real_interface($interface, $family);
+}
+
+function remove_ifindex($ifname) {
+ return preg_replace("/[0-9]+$/", "", $ifname);
+}
+
+?>
diff --git a/src/etc/inc/ipsec.attributes.php b/src/etc/inc/ipsec.attributes.php
new file mode 100644
index 0000000..8a8ed5f
--- /dev/null
+++ b/src/etc/inc/ipsec.attributes.php
@@ -0,0 +1,200 @@
+<?php
+/*
+ ipsec.attributes.php
+ Copyright (C) 2011-2012 Ermal Luçi
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+if (empty($common_name)) {
+ $common_name = getenv("common_name");
+ if (empty($common_name)) {
+ $common_name = getenv("username");
+ }
+}
+
+function cisco_to_cidr($addr) {
+ if (!is_ipaddr($addr)) {
+ return 0;
+ }
+ $mask = decbin(~ip2long($addr));
+ $mask = substr($mask, -32);
+ $k = 0;
+ for ($i = 0; $i <= 32; $i++) {
+ $k += intval($mask[$i]);
+ }
+ return $k;
+}
+
+function cisco_extract_index($prule) {
+
+ $index = explode("#", $prule);
+ if (is_numeric($index[1])) {
+ return intval($index[1]);
+ } else {
+ syslog(LOG_WARNING, "Error parsing rule {$prule}: Could not extract index");
+ }
+ return -1;;
+}
+
+function parse_cisco_acl($attribs) {
+ global $attributes;
+ if (!is_array($attribs)) {
+ return "";
+ }
+
+ $devname = "enc0";
+ $finalrules = "";
+ if (is_array($attribs['ciscoavpair'])) {
+ $inrules = array();
+ $outrules = array();
+ foreach ($attribs['ciscoavpair'] as $avrules) {
+ $rule = explode("=", $avrules);
+ $dir = "";
+ if (strstr($rule[0], "inacl")) {
+ $dir = "in";
+ } else if (strstr($rule[0], "outacl")) {
+ $dir = "out";
+ } else if (strstr($rule[0], "dns-servers")) {
+ $attributes['dns-servers'] = explode(" ", $rule[1]);
+ continue;
+ } else if (strstr($rule[0], "route")) {
+ if (!is_array($attributes['routes'])) {
+ $attributes['routes'] = array();
+ }
+ $attributes['routes'][] = $rule[1];
+ continue;
+ }
+ $rindex = cisco_extract_index($rule[0]);
+ if ($rindex < 0) {
+ continue;
+ }
+
+ $rule = $rule[1];
+ $rule = explode(" ", $rule);
+ $tmprule = "";
+ $index = 0;
+ $isblock = false;
+ if ($rule[$index] == "permit") {
+ $tmprule = "pass {$dir} quick on {$devname} ";
+ } else if ($rule[$index] == "deny") {
+ //continue;
+ $isblock = true;
+ $tmprule = "block {$dir} quick on {$devname} ";
+ } else {
+ continue;
+ }
+
+ $index++;
+
+ switch ($rule[$index]) {
+ case "tcp":
+ case "udp":
+ $tmprule .= "proto {$rule[$index]} ";
+ break;
+ }
+
+ $index++;
+ /* Source */
+ if (trim($rule[$index]) == "host") {
+ $index++;
+ $tmprule .= "from {$rule[$index]} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ } else if (trim($rule[$index]) == "any") {
+ $tmprule .= "from any";
+ $index++;
+ } else {
+ $tmprule .= "from {$rule[$index]}";
+ $index++;
+ $netmask = cisco_to_cidr($rule[$index]);
+ $tmprule .= "/{$netmask} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ }
+ /* Destination */
+ if (trim($rule[$index]) == "host") {
+ $index++;
+ $tmprule .= "to {$rule[$index]} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ } else if (trim($rule[$index]) == "any") {
+ $index++;
+ $tmprule .= "to any";
+ } else {
+ $tmprule .= "to {$rule[$index]}";
+ $index++;
+ $netmask = cisco_to_cidr($rule[$index]);
+ $tmprule .= "/{$netmask} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ }
+
+ if ($isblock == true) {
+ continue;
+ }
+
+ if ($dir == "in") {
+ $inrules[$rindex] = $tmprule;
+ } else if ($dir == "out") {
+ $outrules[$rindex] = $tmprule;
+ }
+ }
+
+
+ $state = "";
+ if (!empty($outrules)) {
+ $state = "no state";
+ }
+ ksort($inrules, SORT_NUMERIC);
+ foreach ($inrules as $inrule) {
+ $finalrules .= "{$inrule} {$state}\n";
+ }
+ if (!empty($outrules)) {
+ ksort($outrules, SORT_NUMERIC);
+ foreach ($outrules as $outrule) {
+ $finalrules .= "{$outrule} {$state}\n";
+ }
+ }
+ }
+ return $finalrules;
+}
+
+$rules = parse_cisco_acl($attributes);
+if (!empty($rules)) {
+ $pid = posix_getpid();
+ @file_put_contents("/tmp/ipsec_{$pid}{$common_name}.rules", $rules);
+ mwexec("/sbin/pfctl -a " . escapeshellarg("ipsec/{$common_name}") . " -f {$g['tmp_path']}/ipsec_{$pid}" . escapeshellarg($common_name) . ".rules");
+ @unlink("{$g['tmp_path']}/ipsec_{$pid}{$common_name}.rules");
+}
+
+?>
diff --git a/src/etc/inc/ipsec.auth-user.php b/src/etc/inc/ipsec.auth-user.php
new file mode 100755
index 0000000..2589598
--- /dev/null
+++ b/src/etc/inc/ipsec.auth-user.php
@@ -0,0 +1,169 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ ipsec.auth-user.php
+
+ Copyright (C) 2008 Shrew Soft Inc
+ Copyright (C) 2010 Ermal Luçi
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+/*
+ pfSense_BUILDER_BINARIES:
+ pfSense_MODULE: openvpn
+*/
+/*
+ * ipsec calls this script to authenticate a user
+ * based on a username and password. We lookup these
+ * in our config.xml file and check the credentials.
+ */
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("radius.inc");
+require_once("auth.inc");
+require_once("interfaces.inc");
+
+/**
+ * Get the NAS-Identifier
+ *
+ * We will use our local hostname to make up the nas_id
+ */
+if (!function_exists("getNasID")) {
+function getNasID() {
+ global $g;
+
+ $nasId = gethostname();
+ if (empty($nasId)) {
+ $nasId = $g['product_name'];
+ }
+ return $nasId;
+}
+}
+
+/**
+ * Get the NAS-IP-Address based on the current wan address
+ *
+ * Use functions in interfaces.inc to find this out
+ *
+ */
+if (!function_exists("getNasIP")) {
+function getNasIP() {
+ $nasIp = get_interface_ip();
+ if (!$nasIp) {
+ $nasIp = "0.0.0.0";
+ }
+ return $nasIp;
+}
+}
+/* setup syslog logging */
+openlog("charon", LOG_ODELAY, LOG_AUTH);
+
+if (isset($_GET['username'])) {
+ $authmodes = explode(",", $_GET['authcfg']);
+ $username = $_GET['username'];
+ $password = $_GET['password'];
+ $common_name = $_GET['cn'];
+} else {
+ /* read data from environment */
+ $username = getenv("username");
+ $password = getenv("password");
+ $common_name = getenv("common_name");
+ $authmodes = explode(",", getenv("authcfg"));
+}
+
+if (!$username || !$password) {
+ syslog(LOG_ERR, "invalid user authentication environment");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ exit (-1);
+ }
+}
+
+$authenticated = false;
+
+if (($strictusercn === true) && ($common_name != $username)) {
+ syslog(LOG_WARNING, "Username does not match certificate common name ({$username} != {$common_name}), access denied.\n");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ exit (1);
+ }
+}
+
+$attributes = array();
+foreach ($authmodes as $authmode) {
+ $authcfg = auth_get_authserver($authmode);
+ if (!$authcfg && $authmode != "local") {
+ continue;
+ }
+
+ $authenticated = authenticate_user($username, $password, $authcfg, $attributes);
+ if ($authenticated == true) {
+ if (stristr($authmode, "local")) {
+ $user = getUserEntry($username);
+ if (!is_array($user) || !userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
+ $authenticated = false;
+ syslog(LOG_WARNING, "user '{$username}' cannot authenticate through IPsec since the required privileges are missing.\n");
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+if ($authenticated == false) {
+ syslog(LOG_WARNING, "user '{$username}' could not authenticate.\n");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ exit (-1);
+ }
+}
+
+if (file_exists("/etc/inc/ipsec.attributes.php")) {
+ include_once("/etc/inc/ipsec.attributes.php");
+}
+
+syslog(LOG_NOTICE, "user '{$username}' authenticated\n");
+closelog();
+
+if (isset($_GET['username'])) {
+ echo "OK";
+} else {
+ exit (0);
+}
+
+?>
diff --git a/src/etc/inc/ipsec.inc b/src/etc/inc/ipsec.inc
new file mode 100644
index 0000000..6654166
--- /dev/null
+++ b/src/etc/inc/ipsec.inc
@@ -0,0 +1,777 @@
+<?php
+/*
+ ipsec.inc
+ Copyright (C) 2007 Scott Ullrich
+ Copyright (C) 2008 Shrew Soft Inc
+ All rights reserved.
+
+ Parts of this code was originally based on vpn_ipsec_sad.php
+ Copyright (C) 2003-2004 Manuel Kasper
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /sbin/setkey /sbin/route
+ pfSense_MODULE: ipsec
+
+*/
+
+/* IPsec defines */
+global $ipsec_loglevels;
+$ipsec_loglevels = array("dmn" => "Daemon", "mgr" => "SA Manager", "ike" => "IKE SA", "chd" => "IKE Child SA",
+ "job" => "Job Processing", "cfg" => "Configuration backend", "knl" => "Kernel Interface",
+ "net" => "Networking", "asn" => "ASN encoding", "enc" => "Message encoding",
+ "imc" => "Integrity checker", "imv" => "Integrity Verifier", "pts" => "Platform Trust Service",
+ "tls" => "TLS handler", "esp" => "IPsec traffic", "lib" => "StrongSwan Lib");
+
+global $my_identifier_list;
+$my_identifier_list = array(
+ 'myaddress' => array('desc' => gettext('My IP address'), 'mobile' => true),
+ 'address' => array('desc' => gettext('IP address'), 'mobile' => true),
+ 'fqdn' => array('desc' => gettext('Distinguished name'), 'mobile' => true),
+ 'user_fqdn' => array('desc' => gettext('User distinguished name'), 'mobile' => true),
+ 'asn1dn' => array('desc' => gettext('ASN.1 distinguished Name'), 'mobile' => true),
+ 'keyid tag' => array('desc' => gettext('KeyID tag'), 'mobile' => true),
+ 'dyn_dns' => array('desc' => gettext('Dynamic DNS'), 'mobile' => true));
+
+global $peer_identifier_list;
+$peer_identifier_list = array(
+ 'any' => array('desc' => gettext('Any'), 'mobile' => true),
+ 'peeraddress' => array('desc' => gettext('Peer IP address'), 'mobile' => false),
+ 'address' => array('desc' => gettext('IP address'), 'mobile' => false),
+ 'fqdn' => array('desc' => gettext('Distinguished name'), 'mobile' => true),
+ 'user_fqdn' => array('desc' => gettext('User distinguished name'), 'mobile' => true),
+ 'asn1dn' => array('desc' => gettext('ASN.1 distinguished Name'), 'mobile' => true),
+ 'keyid tag' => array('desc' =>gettext('KeyID tag'), 'mobile' => true));
+
+global $ipsec_idhandling;
+$ipsec_idhandling = array(
+ 'yes' => 'YES', 'no' => 'NO', 'never' => 'NEVER', 'keep' => 'KEEP'
+ );
+
+global $p1_ealgos;
+$p1_ealgos = array(
+ 'aes' => array('name' => 'AES', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
+ 'aes128gcm' => array('name' => 'AES128-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'aes192gcm' => array('name' => 'AES192-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'aes256gcm' => array('name' => 'AES256-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'blowfish' => array('name' => 'Blowfish', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
+ '3des' => array('name' => '3DES'),
+ 'cast128' => array('name' => 'CAST128'),
+ 'des' => array('name' => 'DES'));
+
+global $p2_ealgos;
+$p2_ealgos = array(
+ 'aes' => array('name' => 'AES', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
+ 'aes128gcm' => array('name' => 'AES128-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'aes192gcm' => array('name' => 'AES192-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'aes256gcm' => array('name' => 'AES256-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
+ 'blowfish' => array('name' => 'Blowfish', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
+ '3des' => array('name' => '3DES'),
+ 'cast128' => array('name' => 'CAST128'),
+ 'des' => array('name' => 'DES'));
+
+global $p1_halgos;
+$p1_halgos = array(
+ 'md5' => 'MD5',
+ 'sha1' => 'SHA1',
+ 'sha256' => 'SHA256',
+ 'sha384' => 'SHA384',
+ 'sha512' => 'SHA512',
+ 'aesxcbc' => 'AES-XCBC'
+);
+
+global $p1_dhgroups;
+$p1_dhgroups = array(
+ 1 => '1 (768 bit)',
+ 2 => '2 (1024 bit)',
+ 5 => '5 (1536 bit)',
+ 14 => '14 (2048 bit)',
+ 15 => '15 (3072 bit)',
+ 16 => '16 (4096 bit)',
+ 17 => '17 (6144 bit)',
+ 18 => '18 (8192 bit)',
+ 19 => '19 (nist ecp256)',
+ 20 => '20 (nist ecp384)',
+ 21 => '21 (nist ecp521)',
+ 22 => '22 (1024(sub 160) bit)',
+ 23 => '23 (2048(sub 224) bit)',
+ 24 => '24 (2048(sub 256) bit)',
+ 28 => '28 (brainpool ecp256)',
+ 29 => '29 (brainpool ecp384)',
+ 30 => '30 (brainpool ecp512)'
+);
+
+global $p2_halgos;
+$p2_halgos = array(
+ 'hmac_md5' => 'MD5',
+ 'hmac_sha1' => 'SHA1',
+ 'hmac_sha256' => 'SHA256',
+ 'hmac_sha384' => 'SHA384',
+ 'hmac_sha512' => 'SHA512',
+ 'aesxcbc' => 'AES-XCBC'
+);
+
+global $p1_authentication_methods;
+$p1_authentication_methods = array(
+ 'hybrid_rsa_server' => array('name' => 'Hybrid RSA + Xauth', 'mobile' => true),
+ 'xauth_rsa_server' => array('name' => 'Mutual RSA + Xauth', 'mobile' => true),
+ 'xauth_psk_server' => array('name' => 'Mutual PSK + Xauth', 'mobile' => true),
+ 'eap-tls' => array('name' => 'EAP-TLS', 'mobile' => true),
+ 'eap-radius' => array('name' => 'EAP-RADIUS', 'mobile' => true),
+ 'eap-mschapv2' => array('name' => 'EAP-MSChapv2', 'mobile' => true),
+ 'rsasig' => array('name' => 'Mutual RSA', 'mobile' => false),
+ 'pre_shared_key' => array('name' => 'Mutual PSK', 'mobile' => false));
+
+global $ipsec_preshared_key_type;
+$ipsec_preshared_key_type = array(
+ 'PSK' => 'PSK',
+ 'EAP' => 'EAP'
+ );
+
+global $p2_modes;
+$p2_modes = array(
+ 'tunnel' => 'Tunnel IPv4',
+ 'tunnel6' => 'Tunnel IPv6',
+ 'transport' => 'Transport');
+
+global $p2_protos;
+$p2_protos = array(
+ 'esp' => 'ESP',
+ 'ah' => 'AH');
+
+global $p2_pfskeygroups;
+$p2_pfskeygroups = array(
+ 0 => 'off',
+ 1 => '1 (768 bit)',
+ 2 => '2 (1024 bit)',
+ 5 => '5 (1536 bit)',
+ 14 => '14 (2048 bit)',
+ 15 => '15 (3072 bit)',
+ 16 => '16 (4096 bit)',
+ 17 => '17 (6144 bit)',
+ 18 => '18 (8192 bit)',
+ 19 => '19 (nist ecp256)',
+ 20 => '20 (nist ecp384)',
+ 21 => '21 (nist ecp521)',
+ 28 => '28 (brainpool ecp256)',
+ 29 => '29 (brainpool ecp384)',
+ 30 => '30 (brainpool ecp512)'
+);
+
+/*
+ * ikeid management functions
+ */
+
+function ipsec_ikeid_used($ikeid) {
+ global $config;
+
+ foreach ($config['ipsec']['phase1'] as $ph1ent) {
+ if ($ikeid == $ph1ent['ikeid']) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function ipsec_ikeid_next() {
+
+ $ikeid = 1;
+ while (ipsec_ikeid_used($ikeid)) {
+ $ikeid++;
+ }
+
+ return $ikeid;
+}
+
+/*
+ * Return phase1 local address
+ */
+function ipsec_get_phase1_src(& $ph1ent) {
+
+ if ($ph1ent['interface']) {
+ if (!is_ipaddr($ph1ent['interface'])) {
+ if (strpos($ph1ent['interface'], '_vip')) {
+ $if = $ph1ent['interface'];
+ } else {
+ $if = get_failover_interface($ph1ent['interface']);
+ }
+ if ($ph1ent['protocol'] == "inet6") {
+ $interfaceip = get_interface_ipv6($if);
+ } else {
+ $interfaceip = get_interface_ip($if);
+ }
+ } else {
+ $interfaceip = $ph1ent['interface'];
+ }
+ } else {
+ $if = "wan";
+ if ($ph1ent['protocol'] == "inet6") {
+ $interfaceip = get_interface_ipv6($if);
+ } else {
+ $interfaceip = get_interface_ip($if);
+ }
+ }
+
+ return $interfaceip;
+}
+
+/*
+ * Return phase1 local address
+ */
+function ipsec_get_phase1_dst(& $ph1ent) {
+ global $g;
+
+ if (empty($ph1ent['remote-gateway'])) {
+ return false;
+ }
+ $rg = $ph1ent['remote-gateway'];
+ if (!is_ipaddr($rg)) {
+ if (!platform_booting()) {
+ return resolve_retry($rg);
+ }
+ }
+ if (!is_ipaddr($rg)) {
+ return false;
+ }
+
+ return $rg;
+}
+
+/*
+ * Return phase2 idinfo in cidr format
+ */
+function ipsec_idinfo_to_cidr(& $idinfo, $addrbits = false, $mode = "") {
+ global $config;
+
+ switch ($idinfo['type']) {
+ case "address":
+ if ($addrbits) {
+ if ($mode == "tunnel6") {
+ return $idinfo['address']."/128";
+ } else {
+ return $idinfo['address']."/32";
+ }
+ } else {
+ return $idinfo['address'];
+ }
+ break; /* NOTREACHED */
+ case "network":
+ return "{$idinfo['address']}/{$idinfo['netbits']}";
+ break; /* NOTREACHED */
+ case "none":
+ case "mobile":
+ return '0.0.0.0/0';
+ break; /* NOTREACHED */
+ default:
+ if (empty($mode) && !empty($idinfo['mode'])) {
+ $mode = $idinfo['mode'];
+ }
+
+ if ($mode == "tunnel6") {
+ $address = get_interface_ipv6($idinfo['type']);
+ $netbits = get_interface_subnetv6($idinfo['type']);
+ $address = gen_subnetv6($address, $netbits);
+ return "{$address}/{$netbits}";
+ } else {
+ $address = get_interface_ip($idinfo['type']);
+ $netbits = get_interface_subnet($idinfo['type']);
+ $address = gen_subnet($address, $netbits);
+ return "{$address}/{$netbits}";
+ }
+ break; /* NOTREACHED */
+ }
+}
+
+/*
+ * Return phase2 idinfo in address/netmask format
+ */
+function ipsec_idinfo_to_subnet(& $idinfo, $addrbits = false) {
+ global $config;
+
+ switch ($idinfo['type']) {
+ case "address":
+ if ($addrbits) {
+ if ($idinfo['mode'] == "tunnel6") {
+ return $idinfo['address']."/128";
+ } else {
+ return $idinfo['address']."/255.255.255.255";
+ }
+ } else {
+ return $idinfo['address'];
+ }
+ break; /* NOTREACHED */
+ case "none":
+ case "network":
+ return $idinfo['address']."/".gen_subnet_mask($idinfo['netbits']);
+ break; /* NOTREACHED */
+ case "mobile":
+ return "0.0.0.0/0";
+ break; /* NOTREACHED */
+ default:
+ if ($idinfo['mode'] == "tunnel6") {
+ $address = get_interface_ipv6($idinfo['type']);
+ $netbits = get_interface_subnetv6($idinfo['type']);
+ $address = gen_subnetv6($address, $netbits);
+ return $address."/".$netbits;
+ } else {
+ $address = get_interface_ip($idinfo['type']);
+ $netbits = get_interface_subnet($idinfo['type']);
+ $address = gen_subnet($address, $netbits);
+ return $address."/".$netbits;
+ }
+ break; /* NOTREACHED */
+ }
+}
+
+/*
+ * Return phase2 idinfo in text format
+ */
+function ipsec_idinfo_to_text(& $idinfo) {
+ global $config;
+
+ switch ($idinfo['type']) {
+ case "address":
+ return $idinfo['address'];
+ break; /* NOTREACHED */
+ case "network":
+ return $idinfo['address']."/".$idinfo['netbits'];
+ break; /* NOTREACHED */
+ case "mobile":
+ return gettext("Mobile Client");
+ break; /* NOTREACHED */
+ case "none":
+ return gettext("None");
+ break; /* NOTREACHED */
+ default:
+ if (!empty($config['interfaces'][$idinfo['type']])) {
+ return convert_friendly_interface_to_friendly_descr($idinfo['type']);
+ } else {
+ return strtoupper($idinfo['type']);
+ }
+ break; /* NOTREACHED */
+ }
+}
+
+/*
+ * Return phase1 association for phase2
+ */
+function ipsec_lookup_phase1(& $ph2ent, & $ph1ent) {
+ global $config;
+
+ if (!is_array($config['ipsec'])) {
+ return false;
+ }
+ if (!is_array($config['ipsec']['phase1'])) {
+ return false;
+ }
+ if (empty($config['ipsec']['phase1'])) {
+ return false;
+ }
+
+ foreach ($config['ipsec']['phase1'] as $ph1tmp) {
+ if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
+ $ph1ent = $ph1tmp;
+ return $ph1ent;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Check phase1 communications status
+ */
+function ipsec_phase1_status(&$ipsec_status, $ikeid) {
+
+ foreach ($ipsec_status as $ike) {
+ if ($ike['id'] == $ikeid) {
+ if ($ike['status'] == 'established') {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Check phase2 communications status
+ */
+function ipsec_phase2_status(&$ipsec_status, &$phase2) {
+
+ if (ipsec_lookup_phase1($ph2ent, $ph1ent)) {
+ return ipsec_phase1_status($ipsec_status, $ph1ent['ikeid']);
+ }
+
+ return false;
+}
+
+function ipsec_smp_dump_status() {
+ global $config, $g, $custom_listtags;
+
+ if (isset($config['ipsec']['enable'])) {
+ if (!file_exists("{$g['varrun_path']}/charon.xml")) {
+ log_error("IPsec daemon not running or has a problem!");
+ return;
+ }
+ } else {
+ return;
+ }
+
+ $fd = @fsockopen("unix://{$g['varrun_path']}/charon.xml");
+ if (!$fd) {
+ log_error("Could not read status from IPsec");
+ return;
+ }
+ $query = '<?xml version="1.0"?><message xmlns="http://www.strongswan.org/smp/1.0" type="request" id="1">';
+ $query .= '<query><ikesalist/></query></message>';
+
+ @fwrite($fd, $query);
+ $response = "";
+ while (!strstr($sread, "</message>")) {
+ $sread = fgets($fd);
+ if ($sread === false) {
+ break;
+ }
+ $response .= $sread;
+ }
+ fclose($fd);
+
+ if ($sread === false) {
+ log_error("Error during reading of status from IPsec");
+ return;
+ }
+
+ @file_put_contents("{$g['tmp_path']}/smp_status.xml", $response);
+ unset($response, $sread);
+
+ $custom_listtags = array('ikesa', 'childsa', 'network', 'auth');
+ $response = parse_xml_config("{$g['tmp_path']}/smp_status.xml", "message");
+ @unlink("{$g['tmp_path']}/smp_status.xml");
+ unset($custom_listtags);
+
+ return $response;
+}
+
+/*
+ * Return dump of SPD table
+ */
+function ipsec_dump_spd() {
+ $fd = @popen("/sbin/setkey -DP", "r");
+ $spd = array();
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = chop(fgets($fd));
+ if (!$line) {
+ continue;
+ }
+ if ($line == "No SPD entries.") {
+ break;
+ }
+ if ($line[0] != "\t") {
+ if (is_array($cursp)) {
+ $spd[] = $cursp;
+ }
+ $cursp = array();
+ $linea = explode(" ", $line);
+ $cursp['srcid'] = substr($linea[0], 0, strpos($linea[0], "["));
+ $cursp['dstid'] = substr($linea[1], 0, strpos($linea[1], "["));
+ $i = 0;
+ } else if (is_array($cursp)) {
+ $line = trim($line, "\t\r\n ");
+ $linea = explode(" ", $line);
+ switch ($i) {
+ case 1:
+ if ($linea[1] == "none") /* don't show default anti-lockout rule */ {
+ unset($cursp);
+ } else {
+ $cursp['dir'] = $linea[0];
+ }
+ break;
+ case 2:
+ $upperspec = explode("/", $linea[0]);
+ $cursp['proto'] = $upperspec[0];
+ list($cursp['src'], $cursp['dst']) = explode("-", $upperspec[2]);
+ $cursp['reqid'] = substr($upperspec[3], strpos($upperspec[3], "#")+1);
+ break;
+ }
+ }
+ $i++;
+ }
+ if (is_array($cursp) && count($cursp)) {
+ $spd[] = $cursp;
+ }
+ pclose($fd);
+ }
+
+ return $spd;
+}
+
+/*
+ * Return dump of SAD table
+ */
+function ipsec_dump_sad() {
+ $fd = @popen("/sbin/setkey -D", "r");
+ $sad = array();
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = chop(fgets($fd));
+ if (!$line || $line[0] == " ") {
+ continue;
+ }
+ if ($line == "No SAD entries.") {
+ break;
+ }
+ if ($line[0] != "\t") {
+ if (is_array($cursa)) {
+ $sad[] = $cursa;
+ }
+ $cursa = array();
+ list($cursa['src'], $cursa['dst']) = explode(" ", $line);
+ } else {
+ $line = trim($line, "\t\n\r ");
+ $linea = explode(" ", $line);
+ foreach ($linea as $idx => $linee) {
+ if ($linee == 'esp' || $linee == 'ah' || $linee[0] == '#') {
+ $cursa['proto'] = $linee;
+ } else if (substr($linee, 0, 3) == 'spi') {
+ $cursa['spi'] = substr($linee, strpos($linee, 'x') + 1, -1);
+ } else if (substr($linee, 0, 5) == 'reqid') {
+ $cursa['reqid'] = substr($linee, strpos($linee, 'x') + 1, -1);
+ } else if (substr($linee, 0, 2) == 'E:') {
+ $cursa['ealgo'] = $linea[$idx + 1];
+ break;
+ } else if (substr($linee, 0, 2) == 'A:') {
+ $cursa['aalgo'] = $linea[$idx + 1];
+ break;
+ } else if (substr($linee, 0, 8) == 'current:') {
+ $cursa['data'] = substr($linea[$idx + 1], 0, strpos($linea[$idx + 1], 'bytes') - 1) . ' B';
+ break;
+ }
+ }
+ }
+ }
+ if (is_array($cursa) && count($cursa)) {
+ $sad[] = $cursa;
+ }
+ pclose($fd);
+ }
+
+ return $sad;
+}
+
+/*
+ * Return dump of mobile user list
+ */
+function ipsec_dump_mobile() {
+ global $g, $custom_listtags;
+
+ $_gb = exec("/usr/local/sbin/ipsec stroke leases > {$g['tmp_path']}/strongswan_leases.xml");
+
+ if (!file_exists("{$g['tmp_path']}/strongswan_leases.xml")) {
+ log_error(gettext("Unable to find IPsec daemon leases file. Could not display mobile user stats!"));
+ return array();
+ }
+
+ /* This is needed for fixing #4130 */
+ if (filesize("{$g['tmp_path']}/strongswan_leases.xml") < 200) {
+ return array();
+ }
+
+ $custom_listtags = array('lease', 'pool');
+ $response = parse_xml_config("{$g['tmp_path']}/strongswan_leases.xml", "leases");
+ @unlink("{$g['tmp_path']}/strongswan_leases.xml");
+ unset($custom_listtags, $_gb);
+
+ return $response;
+}
+
+function ipsec_mobilekey_sort() {
+ global $config;
+
+ function mobilekeycmp($a, $b) {
+ return strcmp($a['ident'][0], $b['ident'][0]);
+ }
+
+ usort($config['ipsec']['mobilekey'], "mobilekeycmp");
+}
+
+function ipsec_get_number_of_phase2($ikeid) {
+ global $config;
+ $a_phase2 = $config['ipsec']['phase2'];
+
+ $nbph2 = 0;
+
+ if (is_array($a_phase2) && count($a_phase2)) {
+ foreach ($a_phase2 as $ph2tmp) {
+ if ($ph2tmp['ikeid'] == $ikeid) {
+ $nbph2++;
+ }
+ }
+ }
+
+ return $nbph2;
+}
+
+function ipsec_get_descr($ikeid) {
+ global $config;
+
+ if (!isset($config['ipsec']['phase1']) ||
+ !is_array($config['ipsec']['phase1'])) {
+ return '';
+ }
+
+ foreach ($config['ipsec']['phase1'] as $p1) {
+ if ($p1['ikeid'] == $ikeid) {
+ return $p1['descr'];
+ }
+ }
+
+ return '';
+}
+
+function ipsec_get_phase1($ikeid) {
+ global $config;
+
+ if (!isset($config['ipsec']['phase1']) ||
+ !is_array($config['ipsec']['phase1'])) {
+ return '';
+ }
+
+ $a_phase1 = $config['ipsec']['phase1'];
+ foreach ($a_phase1 as $p1) {
+ if ($p1['ikeid'] == $ikeid) {
+ return $p1;
+ }
+ }
+ unset($a_phase1);
+}
+
+function ipsec_fixup_ip($ipaddr) {
+ if (is_ipaddrv6($ipaddr) || is_subnetv6($ipaddr)) {
+ return Net_IPv6::compress(Net_IPv6::uncompress($ipaddr));
+ } else {
+ return $ipaddr;
+ }
+}
+
+function ipsec_find_id(& $ph1ent, $side = "local", $rgmap = array()) {
+ if ($side == "local") {
+ $id_type = $ph1ent['myid_type'];
+ $id_data = $ph1ent['myid_data'];
+
+ $addr = ipsec_get_phase1_src($ph1ent);
+ if (!$addr) {
+ return array();
+ }
+ } elseif ($side == "peer") {
+ $id_type = $ph1ent['peerid_type'];
+ $id_data = $ph1ent['peerid_data'];
+
+ if (isset($ph1ent['mobile'])) {
+ $addr = "%any";
+ } else {
+ $addr = $ph1ent['remote-gateway'];
+ }
+ } else {
+ return array();
+ }
+
+
+ $thisid_type = $id_type;
+ switch ($thisid_type) {
+ case 'myaddress':
+ $thisid_type = 'address';
+ $thisid_data = $addr;
+ break;
+ case 'dyn_dns':
+ $thisid_type = 'dns';
+ $thisid_data = $id_data;
+ break;
+ case 'peeraddress':
+ $thisid_type = 'address';
+ $thisid_data = $rgmap[$ph1ent['remote-gateway']];
+ break;
+ case 'address':
+ $thisid_data = $id_data;
+ break;
+ case 'fqdn':
+ $thisid_data = "{$id_data}";
+ break;
+ case 'keyid tag':
+ $thisid_type = 'keyid';
+ $thisid_data = "{$id_data}";
+ break;
+ case 'user_fqdn':
+ $thisid_type = 'userfqdn';
+ $thisid_data = "{$id_data}";
+ break;
+ case 'asn1dn':
+ $thisid_data = $id_data;
+ break;
+ }
+ return array($thisid_type, $thisid_data);
+}
+
+function ipsec_fixup_network($network) {
+ if (substr($network, -3) == '|/0') {
+ $result = substr($network, 0, -3);
+ } else {
+ $tmp = explode('|', $network);
+ if (isset($tmp[1])) {
+ $result = $tmp[1];
+ } else {
+ $result = $tmp[0];
+ }
+ unset($tmp);
+ }
+
+ return $result;
+}
+
+function ipsec_new_reqid() {
+ global $config;
+
+ if (!is_array($config['ipsec']) || !is_array($config['ipsec']['phase2'])) {
+ return;
+ }
+
+ $ipsecreqid = lock('ipsecreqids', LOCK_EX);
+ $keyids = array();
+ $keyid = 1;
+ foreach ($config['ipsec']['phase2'] as $ph2) {
+ $keyids[$ph2['reqid']] = $ph2['reqid'];
+ }
+
+ for ($i = 1; $i < 16000; $i++) {
+ if (!isset($keyids[$i])) {
+ $keyid = $i;
+ break;
+ }
+ }
+ unlock($ipsecreqid);
+
+ return $keyid;
+}
+
+?>
diff --git a/src/etc/inc/itemid.inc b/src/etc/inc/itemid.inc
new file mode 100644
index 0000000..c698cfa
--- /dev/null
+++ b/src/etc/inc/itemid.inc
@@ -0,0 +1,108 @@
+<?php
+
+/*
+ pfSense_MODULE: utils
+*/
+
+/*
+ Copyright (C) 2009 Janne Enberg <janne.enberg@lietu.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/****f* itemid/delete_id
+ * NAME
+ * delete_id - delete an item with ['id'] = $id from $array
+ * INPUTS
+ * $id - int: The ID to delete
+ * $array - array to delete the item from
+ * RESULT
+ * boolean - true if item was found and deleted
+ ******/
+function delete_id($id, &$array) {
+ // Index to delete
+ $delete_index = NULL;
+
+ if (!is_array($array)) {
+ return false;
+ }
+
+ // Search for the item in the array
+ foreach ($array as $key => $item) {
+ // If this item is the one we want to delete
+ if (isset($item['associated-rule-id']) && $item['associated-rule-id'] == $id) {
+ $delete_index = $key;
+ break;
+ }
+ }
+
+ // If we found the item, unset it
+ if ($delete_index !== NULL) {
+ unset($array[$delete_index]);
+ return true;
+ } else {
+ return false;
+ }
+
+}
+
+/****f* itemid/get_id
+ * NAME
+ * get_id - Get an item id with ['associated-rule-id'] = $id from $array
+ * INPUTS
+ * $id - string: The ID to get
+ * $array - array to get the item from
+ * RESULT
+ * mixed - The id, NULL if not found
+ ******/
+function get_id($id, &$array) {
+ // Use $foo = &get_id('id', array('id'=>'value'));
+
+ if (!is_array($array)) {
+ return false;
+ }
+
+ // Search for the item in the array
+ foreach ($array as $key => $item) {
+ // If this item is the one we want to delete
+ if (isset($item['associated-rule-id']) && $item['associated-rule-id'] == $id) {
+ return $key;
+ }
+ }
+
+ return false;
+}
+
+/****f* itemid/get_unique_id
+ * NAME
+ * get_unique_id - get a unique identifier
+ * RESULT
+ * string - unique id
+ ******/
+function get_unique_id() {
+
+ return uniqid("nat_", true);
+}
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/led.inc b/src/etc/inc/led.inc
new file mode 100644
index 0000000..a08eef4
--- /dev/null
+++ b/src/etc/inc/led.inc
@@ -0,0 +1,356 @@
+<?
+/*
+ * led.inc
+ *
+ * (C) 2009 Jim Pingle <jimp@pfsense.org>
+ *
+ * LED control library that wraps around the functionality of led(4)
+ *
+ */
+/*
+ pfSense_BUILDER_BINARIES: /bin/echo
+ pfSense_MODULE: utils
+*/
+
+$led_root = "/dev/led/led";
+
+/*
+ * Send the control string to an LED
+ */
+function led_ctl($led, $str) {
+ global $led_root;
+ if (led_exists($led)) {
+ exec("/bin/echo " . escapeshellarg($str) . " > {$led_root}{$led}");
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Blink an LED at set speed from 1-9 (1=Very Fast, 9=Very Slow)
+ */
+function led_blink($led, $speed = 0) {
+ switch ($speed) {
+ case "reallyfast":
+ case "veryfast":
+ $speed = 1;
+ break;
+ case "fast":
+ $speed = 3;
+ break;
+ case "medium":
+ $speed = 5;
+ break;
+ case "slow":
+ $speed = 7;
+ break;
+ case "reallyslow":
+ case "veryslow":
+ $speed = 9;
+ break;
+ }
+ if (is_numeric($speed) && ($speed > 0) && ($speed < 10)) {
+ return led_ctl($led, "f{$speed}");
+ }
+ return false;
+}
+
+/*
+ * Blink an LED in a specific pattern
+ * Letters A-J are on from 1/10s to 1s
+ * Letters a-j are off from 1/10s to 1s
+ */
+function led_pattern($led, $pattern, $repeat = true) {
+ /* End with a . to stop after one iteration. */
+ $end = $repeat ? "" : ".";
+ return led_ctl($led, "s{$pattern}{$end}");
+}
+
+/*
+ * Encode a text message into morse code, and send it to an LED
+ */
+function led_morse($led, $message) {
+ return led_ctl($led, "m" . str_to_morse($message));
+}
+
+/*
+ * Blink digits out on LED at 1/10s intervals
+ * e.g 1=1 blink, 8=8 blinks
+ * 0 is 10 pulses.
+ * One second pause between digits.
+ */
+function led_digit($led, $digitstring) {
+ $i = 0;
+ $dstring = "d";
+ while ($i < strlen($digitstring)) {
+ $thisdigit = substr($digitstring, $i++, 1);
+ if (is_numeric($thisdigit)) {
+ $dstring .= $thisdigit;
+ }
+ }
+ led_ctl($led, $dstring);
+}
+
+/*
+ * Turn an LED on
+ */
+function led_on($led) {
+ led_ctl($led, "1");
+}
+
+/*
+ * Turn an LED off
+ */
+function led_off($led) {
+ led_ctl($led, "0");
+}
+
+/*
+ * Find the number of LEDs present on the system.
+ */
+function led_count() {
+ global $led_root;
+ $count = 0;
+ $leds = array();
+ if (is_dir(dirname($led_root))) {
+ $leds = glob("{$led_root}*");
+ $count = count($leds);
+ }
+ return $count;
+}
+
+/*
+ * Test to see if a given LED exists.
+ */
+function led_exists($led) {
+ global $led_root;
+ if (!is_numeric($led)) {
+ return false;
+ }
+ return file_exists("{$led_root}{$led}");
+}
+
+/*
+ * Sweep across three LEDs in a K.I.T.T.-like way.
+ */
+function led_kitt() {
+ led_pattern(1, 'AaaaaA');
+ led_pattern(2, 'aAaaAa');
+ led_pattern(3, 'aaAAaa');
+}
+
+/*
+ * Custom pattern for assigning interfaces
+ */
+function led_assigninterfaces() {
+ led_pattern(1, 'AaaAaaaaaaaaaaaa');
+ led_pattern(2, 'aaaaaAaaAaaaaaaa');
+ led_pattern(3, 'aaaaaaaaaaAaaAaa');
+}
+
+/*
+ * Return the three LEDs to a standard setup (1=on, 2 and 3 = off)
+ */
+function led_normalize() {
+ led_on(1);
+ led_off(2);
+ led_off(3);
+}
+
+/*
+ * Shut off ALL LEDs.
+ */
+function led_alloff() {
+ led_off(1);
+ led_off(2);
+ led_off(3);
+}
+
+/*
+ * Translate a string to morse code. Characters not known to have a
+ * valid morse code representation will be ignored.
+ */
+function str_to_morse($string) {
+ $i = 0;
+ $morsestring = "";
+ while ($i < strlen($string)) {
+ $morsestring .= char_to_morse(substr($string, $i++, 1)) . " ";
+ }
+ return $morsestring . "\n";
+}
+
+/*
+ * Translate a single character to morse code. Characters not known
+ * to have a valid morse code representation will be ignored.
+ */
+function char_to_morse($char) {
+ switch (strtoupper($char)) {
+ case "A":
+ return ".-";
+ break;
+ case "B":
+ return "-...";
+ break;
+ case "C":
+ return "-.-.";
+ break;
+ case "D":
+ return "-..";
+ break;
+ case "E":
+ return ".";
+ break;
+ case "F":
+ return "..-.";
+ break;
+ case "G":
+ return "--.";
+ break;
+ case "H":
+ return "....";
+ break;
+ case "I":
+ return "..";
+ break;
+ case "J":
+ return ".---";
+ break;
+ case "K":
+ return "-.-";
+ break;
+ case "L":
+ return ".-..";
+ break;
+ case "M":
+ return "--";
+ break;
+ case "N":
+ return "-.";
+ break;
+ case "O":
+ return "---";
+ break;
+ case "P":
+ return ".--.";
+ break;
+ case "Q":
+ return "--.-";
+ break;
+ case "R":
+ return ".-.";
+ break;
+ case "S":
+ return "...";
+ break;
+ case "T":
+ return "-";
+ break;
+ case "U":
+ return "..-";
+ break;
+ case "V":
+ return "...-";
+ break;
+ case "W":
+ return ".--";
+ break;
+ case "X":
+ return "-..-";
+ break;
+ case "Y":
+ return "-.--";
+ break;
+ case "Z":
+ return "--..";
+ break;
+ case "0":
+ return "-----";
+ break;
+ case "1":
+ return ".----";
+ break;
+ case "2":
+ return "..---";
+ break;
+ case "3":
+ return "...--";
+ break;
+ case "4":
+ return "....-";
+ break;
+ case "5":
+ return ".....";
+ break;
+ case "6":
+ return "-....";
+ break;
+ case "7":
+ return "--...";
+ break;
+ case "8":
+ return "---..";
+ break;
+ case "9":
+ return "----.";
+ break;
+ case ".":
+ return ".-.-.-";
+ break;
+ case ",":
+ return "--..--";
+ break;
+ case "?":
+ return "..--..";
+ break;
+ case "'":
+ return ".----.";
+ break;
+ case "!":
+ return "-.-.--";
+ break;
+ case "/":
+ return "-..-.";
+ break;
+ case "(":
+ return "-.--.";
+ break;
+ case ")":
+ return "-.--.-";
+ break;
+ case "&":
+ return ".-...";
+ break;
+ case ":":
+ return "---...";
+ break;
+ case ";":
+ return "-.-.-.";
+ break;
+ case "=":
+ return "-...-";
+ break;
+ case "+":
+ return ".-.-.";
+ break;
+ case "-":
+ return "-....-";
+ break;
+ case "_":
+ return "..--.-";
+ break;
+ case "$":
+ return "...-..-";
+ break;
+ case "@":
+ return ".--.-.";
+ break;
+ case '"':
+ return ".-..-.";
+ break;
+ default:
+ return "";
+ break;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/login_sasl_client.inc b/src/etc/inc/login_sasl_client.inc
new file mode 100644
index 0000000..f5cc050
--- /dev/null
+++ b/src/etc/inc/login_sasl_client.inc
@@ -0,0 +1,69 @@
+<?php
+/*
+ * login_sasl_client.php
+ *
+ * @(#) $Id: login_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
+ *
+ */
+
+define("SASL_LOGIN_STATE_START", 0);
+define("SASL_LOGIN_STATE_IDENTIFY_USER", 1);
+define("SASL_LOGIN_STATE_IDENTIFY_PASSWORD", 2);
+define("SASL_LOGIN_STATE_DONE", 3);
+
+class login_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_LOGIN_STATE_START;
+
+ Function Initialize(&$client)
+ {
+ return(1);
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if ($this->state!=SASL_LOGIN_STATE_START)
+ {
+ $client->error="LOGIN authentication state is not at the start";
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ "user"=>"",
+ "password"=>"",
+ "realm"=>""
+ );
+ $defaults=array(
+ "realm"=>""
+ );
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if ($status==SASL_CONTINUE)
+ $this->state=SASL_LOGIN_STATE_IDENTIFY_USER;
+ Unset($message);
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch ($this->state)
+ {
+ case SASL_LOGIN_STATE_IDENTIFY_USER:
+ $message=$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "");
+ $this->state=SASL_LOGIN_STATE_IDENTIFY_PASSWORD;
+ break;
+ case SASL_LOGIN_STATE_IDENTIFY_PASSWORD:
+ $message=$this->credentials["password"];
+ $this->state=SASL_LOGIN_STATE_DONE;
+ break;
+ case SASL_LOGIN_STATE_DONE:
+ $client->error="LOGIN authentication was finished without success";
+ break;
+ default:
+ $client->error="invalid LOGIN authentication step state";
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/meta.inc b/src/etc/inc/meta.inc
new file mode 100644
index 0000000..ac8bdfc
--- /dev/null
+++ b/src/etc/inc/meta.inc
@@ -0,0 +1,215 @@
+<?php
+/*
+ Copyright (C) 2008 Shrew Soft Inc
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_MODULE: utils
+
+*/
+
+/*
+ * The meta data format used in pfSense is denoted using markers
+ * followed by the appropriate value or value pair. All markers
+ * are prefixed with a ##| sequence. The + suffix is used to
+ * denote the beginning of a tag block followed by the tag name.
+ * A - suffix is used to denote the end of a tag block. Values
+ * are denoted using the * suffix and can optionally be expressed
+ * as a key value pair. An example of a metadata tag block ...
+ *
+ * ###|+INFO
+ * ###|*BLAH
+ * ###|*TEXT=SOME TEXT
+ * ###|-INFO
+ *
+ * After calling read_file_metadata, the result array would
+ * contain the following information ...
+ *
+ * metadata['<filename>']['INFO']['BLAH'][0] == true
+ * metadata['<filename>']['INFO']['TEXT'][0] == "SOME TEXT"
+ *
+ * NOTE: All statements must be at the beginning of a line and
+ * contiguous for a tag. The example shown above would not be
+ * processed due to the extra ' * ' comment chars.
+ *
+ */
+
+/*
+ * locate php files for a given path
+ */
+
+function list_phpfiles($path, & $found) {
+
+ if (!is_array($found)) {
+ $found = array();
+ }
+
+ $dir = opendir($path);
+ if (!$dir) {
+ printf(gettext("list_phpfiles: unable to examine path %s\n"), $path);
+ return;
+ }
+
+ while ($fname = readdir($dir)) {
+ if ($fname == "." || $fname == ".." || $fname[0] == '.') {
+ continue;
+ }
+ if (fnmatch('*.php', $fname)) {
+ $found[] = $fname;
+ }
+ }
+}
+
+/*
+ * read embedded metadata from a file
+ */
+
+function read_file_metadata($fpath, & $metadata, $taglist = false) {
+
+ if (!is_array($metadata)) {
+ $metadata = array();
+ }
+
+ if ($taglist) {
+ $taglist = explode(",", $taglist);
+ }
+
+ $fname = $fpath;
+ $slash = strrpos($fname, "/");
+ if ($slash) {
+ $fname = substr($fname, $slash + 1);
+ }
+
+ $fdata = @file_get_contents($fpath);
+ if (!$fdata) {
+ printf(gettext("unable to read %s\n"), $fpath);
+ continue;
+ }
+
+ $offset = 0;
+
+ $tags = array();
+
+ while (true) {
+
+ $tagbeg_off = stripos($fdata, "##|+", $offset);
+ if ($tagbeg_off === false) {
+ break;
+ }
+
+ $tagbeg_trm = stripos($fdata, "\n", $tagbeg_off);
+ if ($tagbeg_trm === false) {
+ break;
+ }
+
+ $tagend_off = stripos($fdata, "##|-", $tagbeg_trm);
+ if ($tagend_off === false) {
+ break;
+ }
+
+ $tagend_trm = stripos($fdata, "\n", $tagend_off);
+ if ($tagend_trm === false) {
+ break;
+ }
+
+ $tagbeg_len = $tagbeg_trm - $tagbeg_off;
+ $tagend_len = $tagend_trm - $tagend_off;
+
+ $tagbeg = substr($fdata, $tagbeg_off + 4, $tagbeg_len - 4);
+ $tagend = substr($fdata, $tagend_off + 4, $tagend_len - 4);
+
+ if ($tagbeg != $tagend) {
+ printf(gettext("error: tag mismatch ( %1\$s != %2\$s ) in '%3\$s'%4\$s"), $tagbeg, $tagend, $fpath, "\n");
+ break;
+ }
+
+ $mdata_off = $tagbeg_trm + 1;
+ $mdata_trm = $tagend_off - 1;
+ $mdata_len = $mdata_trm - $mdata_off;
+
+ $mdata = substr($fdata, $mdata_off, $mdata_len);
+
+ if (!strlen($mdata)) {
+ printf(gettext("warning: tag %1\$s has no data in '%2\$s'%3\$s"), $tagbeg, $fpath, "\n");
+ break;
+ }
+
+ $offset = $tagend_trm + 1;
+
+ if (is_array($taglist)) {
+ if (!in_array($tagbeg, $taglist)) {
+ continue;
+ }
+ }
+
+ $vals = array();
+
+ $lines = explode("\n", $mdata);
+ foreach ($lines as $line) {
+
+ if (!strlen($line)) {
+ continue;
+ }
+
+ $valtag = stripos($line, "##|*");
+ if ($valtag === false || $valtag) {
+ printf(gettext("warning: tag %1\$s has malformed data in '%2\$s'%3\$s"), $tagbeg, $fpath, "\n");
+ continue;
+ }
+
+ $value = substr($line, 4, strlen($line) - 1);
+ $vlist = explode("=", $value);
+
+ unset($vname);
+ unset($vdata);
+
+ switch (count($vlist)) {
+ case 1:
+ $vname = $vlist[0];
+ $vdata = true;
+ break;
+ case 2:
+ $vname = $vlist[0];
+ $vdata = $vlist[1];
+ break;
+ }
+
+ if (!isset($vname) || !isset($vdata)) {
+ printf(gettext("warning: tag %1\$s has invalid data in '%2\$s'%3\$s"), $tagbeg, $fpath, "\n");
+ continue;
+ }
+
+ $vals[$vname][] = $vdata;
+ }
+
+ if (count($vals)) {
+ $tags[$tagbeg] = $vals;
+ }
+ }
+
+ if (count($tags)) {
+ $metadata[$fname] = $tags;
+ }
+}
+
+?>
diff --git a/src/etc/inc/notices.inc b/src/etc/inc/notices.inc
new file mode 100644
index 0000000..891c18b
--- /dev/null
+++ b/src/etc/inc/notices.inc
@@ -0,0 +1,453 @@
+<?php
+/****h* pfSense/notices
+ NAME
+ notices.inc - pfSense notice utilities
+ DESCRIPTION
+ This include contains the pfSense notice facilities.
+ HISTORY
+ $Id$
+
+ Copyright (C) 2009 Scott Ullrich (sullrich@gmail.com)
+ Copyright (C) 2005 Colin Smith (ethethlay@gmail.com)
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ pfSense_BUILDER_BINARIES: /bin/echo
+ pfSense_MODULE: notifications
+*/
+
+require_once("globals.inc");
+require_once("led.inc");
+
+$notice_path = $g['tmp_path'] . '/notices';
+$smtp_authentication_mechanisms = array(
+ 'PLAIN' => 'PLAIN',
+ 'LOGIN' => 'LOGIN');
+/* Other SMTP Authentication Mechanisms that could be supported.
+ * Note that MD5 is no longer considered secure.
+ * 'GSSAPI' => 'GSSAPI ' . gettext("Generic Security Services Application Program Interface")
+ * 'DIGEST-MD5' => 'DIGEST-MD5 ' . gettext("Digest access authentication")
+ * 'MD5' => 'MD5'
+ * 'CRAM-MD5' => 'CRAM-MD5'
+*/
+
+/****f* notices/file_notice
+ * NAME
+ * file_notice
+ * INPUTS
+ * $id, $notice, $category, $url, $priority
+ * RESULT
+ * Files a notice and kicks off the various alerts, smtp, growl, system log, LED's, etc.
+ ******/
+function file_notice($id, $notice, $category = "General", $url = "", $priority = 1) {
+ /*
+ * $category - Category that this notice should be displayed under. This can be arbitrary,
+ * but a page must be set to receive this messages for it to be displayed.
+ *
+ * $priority - A notice's priority. Higher numbers indicate greater severity.
+ * 0 = informational, 1 = warning, 2 = error, etc. This may also be arbitrary,
+ */
+ global $notice_path;
+ if (!$queue = get_notices()) {
+ $queue = array();
+ }
+ $queuekey = time();
+ $toqueue = array(
+ 'id' => $id,
+ 'notice' => $notice,
+ 'url' => $url,
+ 'category' => $category,
+ 'priority' => $priority,
+ );
+ $queue[$queuekey] = $toqueue;
+ $queueout = fopen($notice_path, "w");
+ if (!$queueout) {
+ log_error(printf(gettext("Could not open %s for writing"), $notice_path));
+ return;
+ }
+ fwrite($queueout, serialize($queue));
+ fclose($queueout);
+ log_error("New alert found: $notice");
+ /* soekris */
+ if (file_exists("/dev/led/error")) {
+ exec("/bin/echo 1 > /dev/led/error");
+ }
+ /* wrap & alix */
+ led_normalize();
+ led_morse(1, 'sos');
+ notify_via_growl($notice);
+ notify_via_smtp($notice);
+ return $queuekey;
+}
+
+/****f* notices/get_notices
+ * NAME
+ * get_notices
+ * INPUTS
+ * $category
+ * RESULT
+ * Returns a specific notices text
+ ******/
+function get_notices($category = "all") {
+ global $g;
+
+ if (file_exists("{$g['tmp_path']}/notices")) {
+ $queue = unserialize(file_get_contents("{$g['tmp_path']}/notices"));
+ if (!$queue) {
+ return false;
+ }
+ if ($category != 'all') {
+ foreach ($queue as $time => $notice) {
+ if (strtolower($notice['category']) == strtolower($category)) {
+ $toreturn[$time] = $notice;
+ }
+ }
+ return $toreturn;
+ } else {
+ return $queue;
+ }
+ } else {
+ return false;
+ }
+}
+
+/****f* notices/close_notice
+ * NAME
+ * close_notice
+ * INPUTS
+ * $id
+ * RESULT
+ * Removes a notice from the list
+ ******/
+function close_notice($id) {
+ global $notice_path;
+ require_once("util.inc");
+ /* soekris */
+ if (file_exists("/dev/led/error")) {
+ exec("/bin/echo 0 > /dev/led/error");
+ }
+ /* wrap & alix */
+ led_normalize();
+ $ids = array();
+ if (!$notices = get_notices()) {
+ return;
+ }
+ if ($id == "all") {
+ unlink_if_exists($notice_path);
+ return;
+ }
+ foreach (array_keys($notices) as $time) {
+ if ($id == $time) {
+ unset($notices[$id]);
+ break;
+ }
+ }
+ foreach ($notices as $key => $notice) {
+ $ids[$key] = $notice['id'];
+ }
+ foreach ($ids as $time => $tocheck) {
+ if ($id == $tocheck) {
+ unset($notices[$time]);
+ break;
+ }
+ }
+ if (count($notices) != 0) {
+ $queueout = fopen($notice_path, "w");
+ fwrite($queueout, serialize($notices));
+ fclose($queueout);
+ } else {
+ unlink_if_exists($notice_path);
+ }
+
+ return;
+}
+
+/****f* notices/dump_xml_notices
+ * NAME
+ * dump_xml_notices
+ * INPUTS
+ * NONE
+ * RESULT
+ * Outputs notices in XML formatted text
+ ******/
+function dump_xml_notices() {
+ if (file_exists("/cf/conf/use_xmlreader")) {
+ require_once("xmlreader.inc");
+ } else {
+ require_once("xmlparse.inc");
+ }
+ global $notice_path, $listtags;
+ $listtags[] = 'notice';
+ if (!$notices = get_notices()) {
+ return;
+ }
+ foreach ($notices as $time => $notice) {
+ $notice['time'] = $time;
+ $toput['notice'][] = $notice;
+ }
+ $xml = dump_xml_config($toput, 'notices');
+ return $xml;
+}
+
+/****f* notices/print_notices
+ * NAME
+ * print_notices
+ * INPUTS
+ * $notices, $category
+ * RESULT
+ * prints notices to the GUI
+ ******/
+function print_notices($notices, $category = "all") {
+ foreach ($notices as $notice) {
+ if ($category != "all") {
+ if (in_array($notice['category'], $category)) {
+ $categories[] = $notice['category'];
+ }
+ } else {
+ $categories[] = $notice['category'];
+ }
+ }
+ $categories = array_unique($categories);
+ sort($categories);
+ foreach ($categories as $category) {
+ $toreturn .= "<ul><li>{$category}<ul>";
+ foreach ($notices as $notice) {
+ if (strtolower($notice['category']) == strtolower($category)) {
+ if ($notice['id'] != "") {
+ if ($notice['url'] != "") {
+ $toreturn .= "<li><a href={$notice['url']}>{$notice['id']}</a> - {$notice['notice']}</li>";
+ } else {
+ $toreturn .= "<li>{$notice['id']} - {$notice['notice']}</li>";
+ }
+ }
+ }
+ }
+ $toreturn .= "</ul></li></ul>";
+ }
+ return $toreturn;
+}
+
+/****f* notices/print_notice_box
+ * NAME
+ * print_notice_box
+ * INPUTS
+ * $category
+ * RESULT
+ * prints an info box to the GUI
+ ******/
+function print_notice_box($category = "all") {
+ $notices = get_notices();
+ if (!$notices) {
+ return;
+ }
+ print_info_box_np(print_notices($notices, $category));
+ return;
+}
+
+/****f* notices/are_notices_pending
+ * NAME
+ * are_notices_pending
+ * INPUTS
+ * $category to check
+ * RESULT
+ * returns true if notices are pending, false if they are not
+ ******/
+function are_notices_pending($category = "all") {
+ global $notice_path;
+ if (file_exists($notice_path)) {
+ return true;
+ }
+ return false;
+}
+
+/****f* notices/notify_via_smtp
+ * NAME
+ * notify_via_smtp
+ * INPUTS
+ * notification string to send as an email
+ * RESULT
+ * returns true if message was sent
+ ******/
+function notify_via_smtp($message, $force = false) {
+ global $config, $g;
+ if (platform_booting()) {
+ return;
+ }
+
+ if (isset($config['notifications']['smtp']['disable']) && !$force) {
+ return;
+ }
+
+ /* Do NOT send the same message twice */
+ if (file_exists("/var/db/notices_lastmsg.txt")) {
+ $lastmsg = trim(file_get_contents("/var/db/notices_lastmsg.txt"));
+ if ($lastmsg == $message) {
+ return;
+ }
+ }
+
+ /* Store last message sent to avoid spamming */
+ $fd = fopen("/var/db/notices_lastmsg.txt", "w");
+ fwrite($fd, $message);
+ fclose($fd);
+
+ send_smtp_message($message, "{$config['system']['hostname']}.{$config['system']['domain']} - Notification", $force);
+ return;
+}
+
+function send_smtp_message($message, $subject = "(no subject)", $force = false) {
+ global $config, $g;
+ require_once("sasl.inc");
+ require_once("smtp.inc");
+
+ if (isset($config['notifications']['smtp']['disable']) && !$force) {
+ return;
+ }
+
+ if (!$config['notifications']['smtp']['ipaddress']) {
+ return;
+ }
+
+ if (!$config['notifications']['smtp']['notifyemailaddress']) {
+ return;
+ }
+
+ $smtp = new smtp_class;
+
+ $from = "pfsense@{$config['system']['hostname']}.{$config['system']['domain']}";
+ $to = $config['notifications']['smtp']['notifyemailaddress'];
+
+ $smtp->host_name = $config['notifications']['smtp']['ipaddress'];
+ $smtp->host_port = empty($config['notifications']['smtp']['port']) ? 25 : $config['notifications']['smtp']['port'];
+
+ $smtp->direct_delivery = 0;
+ $smtp->ssl = (isset($config['notifications']['smtp']['ssl'])) ? 1 : 0;
+ $smtp->tls = (isset($config['notifications']['smtp']['tls'])) ? 1 : 0;
+ $smtp->debug = 0;
+ $smtp->html_debug = 0;
+ $smtp->localhost = $config['system']['hostname'] . "." . $config['system']['domain'];
+
+ if ($config['notifications']['smtp']['fromaddress']) {
+ $from = $config['notifications']['smtp']['fromaddress'];
+ }
+
+ // Use SMTP Auth if fields are filled out
+ if ($config['notifications']['smtp']['username'] &&
+ $config['notifications']['smtp']['password']) {
+ if (isset($config['notifications']['smtp']['authentication_mechanism'])) {
+ $smtp->authentication_mechanism = $config['notifications']['smtp']['authentication_mechanism'];
+ } else {
+ $smtp->authentication_mechanism = "PLAIN";
+ }
+ $smtp->user = $config['notifications']['smtp']['username'];
+ $smtp->password = $config['notifications']['smtp']['password'];
+ }
+
+ $headers = array(
+ "From: {$from}",
+ "To: {$to}",
+ "Subject: {$subject}",
+ "Date: " . date("r")
+ );
+
+ if ($smtp->SendMessage($from, preg_split('/\s*,\s*/', trim($to)), $headers, $message)) {
+ log_error(sprintf(gettext("Message sent to %s OK"), $to));
+ return;
+ } else {
+ log_error(sprintf(gettext('Could not send the message to %1$s -- Error: %2$s'), $to, $smtp->error));
+ return(sprintf(gettext('Could not send the message to %1$s -- Error: %2$s'), $to, $smtp->error));
+ }
+}
+
+/****f* notices/notify_via_growl
+ * NAME
+ * notify_via_growl
+ * INPUTS
+ * notification string to send
+ * RESULT
+ * returns true if message was sent
+ ******/
+function notify_via_growl($message, $force=false) {
+ require_once("growl.class");
+ global $config, $g;
+
+ if (isset($config['notifications']['growl']['disable']) && !$force) {
+ return;
+ }
+
+ /* Do NOT send the same message twice */
+ if (file_exists("/var/db/growlnotices_lastmsg.txt")) {
+ $lastmsg = trim(file_get_contents("/var/db/growlnotices_lastmsg.txt"));
+ if ($lastmsg == $message) {
+ return;
+ }
+ }
+
+ $hostname = $config['system']['hostname'] . "." . $config['system']['domain'];
+ $growl_ip = $config['notifications']['growl']['ipaddress'];
+ $growl_password = $config['notifications']['growl']['password'];
+ $growl_name = $config['notifications']['growl']['name'];
+ $growl_notification = $config['notifications']['growl']['notification_name'];
+
+ if (!empty($growl_ip) && (is_ipaddr($growl_ip) || dns_get_record($growl_ip, DNS_A) || dns_get_record($growl_ip, DNS_AAAA))) {
+ $growl = new Growl($growl_ip, $growl_password, $growl_name);
+ $growl->notify("{$growl_notification}", gettext(sprintf("%s (%s) - Notification", $g['product_name'], $hostname)), "{$message}");
+ }
+
+ /* Store last message sent to avoid spamming */
+ $fd = fopen("/var/db/growlnotices_lastmsg.txt", "w");
+ fwrite($fd, $message);
+ fclose($fd);
+}
+
+/****f* notices/register_via_growl
+ * NAME
+ * register_via_growl
+ * INPUTS
+ * none
+ * RESULT
+ * none
+ ******/
+function register_via_growl() {
+ require_once("growl.class");
+ global $config;
+ $growl_ip = $config['notifications']['growl']['ipaddress'];
+ $growl_password = $config['notifications']['growl']['password'];
+ $growl_name = $config['notifications']['growl']['name'];
+ $growl_notification = $config['notifications']['growl']['notification_name'];
+
+ if ($growl_ip) {
+ $growl = new Growl($growl_ip, $growl_password, $growl_name);
+ $growl->addNotification($growl_notification);
+ $growl->register();
+ }
+}
+
+/* Notify via remote methods only - not via GUI. */
+function notify_all_remote($msg) {
+ notify_via_smtp($msg);
+ notify_via_growl($msg);
+}
+
+?>
diff --git a/src/etc/inc/ntlm_sasl_client.inc b/src/etc/inc/ntlm_sasl_client.inc
new file mode 100644
index 0000000..18e5658
--- /dev/null
+++ b/src/etc/inc/ntlm_sasl_client.inc
@@ -0,0 +1,180 @@
+<?php
+/*
+ * ntlm_sasl_client.php
+ *
+ * @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
+ *
+ */
+
+define("SASL_NTLM_STATE_START", 0);
+define("SASL_NTLM_STATE_IDENTIFY_DOMAIN", 1);
+define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2);
+define("SASL_NTLM_STATE_DONE", 3);
+
+class ntlm_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_NTLM_STATE_START;
+
+ Function Initialize(&$client)
+ {
+ if (!function_exists($function="mcrypt_encrypt") ||
+ !function_exists($function="hash"))
+ {
+ $extensions=array(
+ "mcrypt_encrypt"=>"mcrypt",
+ "hash"=>"hash"
+ );
+ $client->error="the extension ".$extensions[$function]." required by the NTLM SASL client class is not available in this PHP configuration";
+ return(0);
+ }
+ return(1);
+ }
+
+ Function ASCIIToUnicode($ascii)
+ {
+ for ($unicode="",$a=0;$a<strlen($ascii);$a++)
+ $unicode.=substr($ascii,$a,1).chr(0);
+ return($unicode);
+ }
+
+ Function TypeMsg1($domain,$workstation)
+ {
+ $domain_length=strlen($domain);
+ $workstation_length=strlen($workstation);
+ $workstation_offset=32;
+ $domain_offset=$workstation_offset+$workstation_length;
+ return(
+ "NTLMSSP\0".
+ "\x01\x00\x00\x00".
+ "\x07\x32\x00\x00".
+ pack("v",$domain_length).
+ pack("v",$domain_length).
+ pack("V",$domain_offset).
+ pack("v",$workstation_length).
+ pack("v",$workstation_length).
+ pack("V",$workstation_offset).
+ $workstation.
+ $domain
+ );
+ }
+
+ Function NTLMResponse($challenge,$password)
+ {
+ $unicode=$this->ASCIIToUnicode($password);
+ $md4=hash("md4", $unicode);
+ $padded=$md4.str_repeat(chr(0),21-strlen($md4));
+ $iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB);
+ $iv=mcrypt_create_iv($iv_size,MCRYPT_RAND);
+ for ($response="",$third=0;$third<21;$third+=7)
+ {
+ for ($packed="",$p=$third;$p<$third+7;$p++)
+ $packed.=str_pad(decbin(ord(substr($padded,$p,1))),8,"0",STR_PAD_LEFT);
+ for ($key="",$p=0;$p<strlen($packed);$p+=7)
+ {
+ $s=substr($packed,$p,7);
+ $b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
+ $key.=chr(bindec($b));
+ }
+ $ciphertext=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv);
+ $response.=$ciphertext;
+ }
+ return $response;
+ }
+
+ Function TypeMsg3($ntlm_response,$user,$domain,$workstation)
+ {
+ $domain_unicode=$this->ASCIIToUnicode($domain);
+ $domain_length=strlen($domain_unicode);
+ $domain_offset=64;
+ $user_unicode=$this->ASCIIToUnicode($user);
+ $user_length=strlen($user_unicode);
+ $user_offset=$domain_offset+$domain_length;
+ $workstation_unicode=$this->ASCIIToUnicode($workstation);
+ $workstation_length=strlen($workstation_unicode);
+ $workstation_offset=$user_offset+$user_length;
+ $lm="";
+ $lm_length=strlen($lm);
+ $lm_offset=$workstation_offset+$workstation_length;
+ $ntlm=$ntlm_response;
+ $ntlm_length=strlen($ntlm);
+ $ntlm_offset=$lm_offset+$lm_length;
+ $session="";
+ $session_length=strlen($session);
+ $session_offset=$ntlm_offset+$ntlm_length;
+ return(
+ "NTLMSSP\0".
+ "\x03\x00\x00\x00".
+ pack("v",$lm_length).
+ pack("v",$lm_length).
+ pack("V",$lm_offset).
+ pack("v",$ntlm_length).
+ pack("v",$ntlm_length).
+ pack("V",$ntlm_offset).
+ pack("v",$domain_length).
+ pack("v",$domain_length).
+ pack("V",$domain_offset).
+ pack("v",$user_length).
+ pack("v",$user_length).
+ pack("V",$user_offset).
+ pack("v",$workstation_length).
+ pack("v",$workstation_length).
+ pack("V",$workstation_offset).
+ pack("v",$session_length).
+ pack("v",$session_length).
+ pack("V",$session_offset).
+ "\x01\x02\x00\x00".
+ $domain_unicode.
+ $user_unicode.
+ $workstation_unicode.
+ $lm.
+ $ntlm
+ );
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if ($this->state!=SASL_NTLM_STATE_START)
+ {
+ $client->error="NTLM authentication state is not at the start";
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ "user"=>"",
+ "password"=>"",
+ "realm"=>"",
+ "workstation"=>""
+ );
+ $defaults=array();
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if ($status==SASL_CONTINUE)
+ $this->state=SASL_NTLM_STATE_IDENTIFY_DOMAIN;
+ Unset($message);
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch ($this->state)
+ {
+ case SASL_NTLM_STATE_IDENTIFY_DOMAIN:
+ $message=$this->TypeMsg1($this->credentials["realm"],$this->credentials["workstation"]);
+ $this->state=SASL_NTLM_STATE_RESPOND_CHALLENGE;
+ break;
+ case SASL_NTLM_STATE_RESPOND_CHALLENGE:
+ $ntlm_response=$this->NTLMResponse(substr($response,24,8),$this->credentials["password"]);
+ $message=$this->TypeMsg3($ntlm_response,$this->credentials["user"],$this->credentials["realm"],$this->credentials["workstation"]);
+ $this->state=SASL_NTLM_STATE_DONE;
+ break;
+ case SASL_NTLM_STATE_DONE:
+ $client->error="NTLM authentication was finished without success";
+ return(SASL_FAIL);
+ default:
+ $client->error="invalid NTLM authentication step state";
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?>
diff --git a/src/etc/inc/openvpn.attributes.php b/src/etc/inc/openvpn.attributes.php
new file mode 100644
index 0000000..467d691
--- /dev/null
+++ b/src/etc/inc/openvpn.attributes.php
@@ -0,0 +1,203 @@
+<?php
+/*
+ openvpn.attributes.php
+ Copyright (C) 2011-2012 Ermal Luçi
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+if (empty($common_name)) {
+ $common_name = getenv("common_name");
+ if (empty($common_name)) {
+ $common_name = getenv("username");
+ }
+}
+
+$devname = getenv("dev");
+if (empty($devname)) {
+ $devname = "openvpn";
+}
+
+function cisco_to_cidr($addr) {
+ if (!is_ipaddr($addr)) {
+ return 0;
+ }
+ $mask = decbin(~ip2long($addr));
+ $mask = substr($mask, -32);
+ $k = 0;
+ for ($i = 0; $i <= 32; $i++) {
+ $k += intval($mask[$i]);
+ }
+ return $k;
+}
+
+function cisco_extract_index($prule) {
+
+ $index = explode("#", $prule);
+ if (is_numeric($index[1])) {
+ return intval($index[1]);
+ } else {
+ syslog(LOG_WARNING, "Error parsing rule {$prule}: Could not extract index");
+ }
+ return -1;;
+}
+
+function parse_cisco_acl($attribs) {
+ global $devname, $attributes;
+ if (!is_array($attribs)) {
+ return "";
+ }
+ $finalrules = "";
+ if (is_array($attribs['ciscoavpair'])) {
+ $inrules = array();
+ $outrules = array();
+ foreach ($attribs['ciscoavpair'] as $avrules) {
+ $rule = explode("=", $avrules);
+ $dir = "";
+ if (strstr($rule[0], "inacl")) {
+ $dir = "in";
+ } else if (strstr($rule[0], "outacl")) {
+ $dir = "out";
+ } else if (strstr($rule[0], "dns-servers")) {
+ $attributes['dns-servers'] = explode(" ", $rule[1]);
+ continue;
+ } else if (strstr($rule[0], "route")) {
+ if (!is_array($attributes['routes'])) {
+ $attributes['routes'] = array();
+ }
+ $attributes['routes'][] = $rule[1];
+ continue;
+ }
+ $rindex = cisco_extract_index($rule[0]);
+ if ($rindex < 0) {
+ continue;
+ }
+
+ $rule = $rule[1];
+ $rule = explode(" ", $rule);
+ $tmprule = "";
+ $index = 0;
+ $isblock = false;
+ if ($rule[$index] == "permit") {
+ $tmprule = "pass {$dir} quick on {$devname} ";
+ } else if ($rule[$index] == "deny") {
+ //continue;
+ $isblock = true;
+ $tmprule = "block {$dir} quick on {$devname} ";
+ } else {
+ continue;
+ }
+
+ $index++;
+
+ switch ($rule[$index]) {
+ case "tcp":
+ case "udp":
+ $tmprule .= "proto {$rule[$index]} ";
+ break;
+ }
+
+ $index++;
+ /* Source */
+ if (trim($rule[$index]) == "host") {
+ $index++;
+ $tmprule .= "from {$rule[$index]} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ } else if (trim($rule[$index]) == "any") {
+ $tmprule .= "from any";
+ $index++;
+ } else {
+ $tmprule .= "from {$rule[$index]}";
+ $index++;
+ $netmask = cisco_to_cidr($rule[$index]);
+ $tmprule .= "/{$netmask} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ }
+ /* Destination */
+ if (trim($rule[$index]) == "host") {
+ $index++;
+ $tmprule .= "to {$rule[$index]} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ } else if (trim($rule[$index]) == "any") {
+ $index++;
+ $tmprule .= "to any";
+ } else {
+ $tmprule .= "to {$rule[$index]}";
+ $index++;
+ $netmask = cisco_to_cidr($rule[$index]);
+ $tmprule .= "/{$netmask} ";
+ $index++;
+ if ($isblock == true) {
+ $isblock = false;
+ }
+ }
+
+ if ($isblock == true) {
+ continue;
+ }
+
+ if ($dir == "in") {
+ $inrules[$rindex] = $tmprule;
+ } else if ($dir == "out") {
+ $outrules[$rindex] = $tmprule;
+ }
+ }
+
+
+ $state = "";
+ if (!empty($outrules)) {
+ $state = "no state";
+ }
+ ksort($inrules, SORT_NUMERIC);
+ foreach ($inrules as $inrule) {
+ $finalrules .= "{$inrule} {$state}\n";
+ }
+ if (!empty($outrules)) {
+ ksort($outrules, SORT_NUMERIC);
+ foreach ($outrules as $outrule) {
+ $finalrules .= "{$outrule} {$state}\n";
+ }
+ }
+ }
+ return $finalrules;
+}
+
+$rules = parse_cisco_acl($attributes);
+if (!empty($rules)) {
+ $pid = posix_getpid();
+ @file_put_contents("/tmp/ovpn_{$pid}{$common_name}.rules", $rules);
+ mwexec("/sbin/pfctl -a " . escapeshellarg("openvpn/{$common_name}") . " -f {$g['tmp_path']}/ovpn_{$pid}" . escapeshellarg($common_name) . ".rules");
+ @unlink("{$g['tmp_path']}/ovpn_{$pid}{$common_name}.rules");
+}
+
+?>
diff --git a/src/etc/inc/openvpn.auth-user.php b/src/etc/inc/openvpn.auth-user.php
new file mode 100644
index 0000000..e108a4f
--- /dev/null
+++ b/src/etc/inc/openvpn.auth-user.php
@@ -0,0 +1,213 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ openvpn.auth-user.php
+
+ Copyright (C) 2008 Shrew Soft Inc
+ Copyright (C) 2010 Ermal Luçi
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+/*
+ pfSense_BUILDER_BINARIES:
+ pfSense_MODULE: openvpn
+*/
+/*
+ * OpenVPN calls this script to authenticate a user
+ * based on a username and password. We lookup these
+ * in our config.xml file and check the credentials.
+ */
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("radius.inc");
+require_once("auth.inc");
+require_once("interfaces.inc");
+
+/**
+ * Get the NAS-Identifier
+ *
+ * We will use our local hostname to make up the nas_id
+ */
+if (!function_exists("getNasID")) {
+function getNasID() {
+ global $g;
+
+ $nasId = gethostname();
+ if (empty($nasId)) {
+ $nasId = $g['product_name'];
+ }
+ return $nasId;
+}
+}
+
+/**
+ * Get the NAS-IP-Address based on the current wan address
+ *
+ * Use functions in interfaces.inc to find this out
+ *
+ */
+if (!function_exists("getNasIP")) {
+function getNasIP() {
+ $nasIp = get_interface_ip();
+ if (!$nasIp) {
+ $nasIp = "0.0.0.0";
+ }
+ return $nasIp;
+}
+}
+/* setup syslog logging */
+openlog("openvpn", LOG_ODELAY, LOG_AUTH);
+
+if (isset($_GET['username'])) {
+ $authmodes = explode(",", $_GET['authcfg']);
+ $username = base64_decode(str_replace('%3D', '=', $_GET['username']));
+ $password = base64_decode(str_replace('%3D', '=', $_GET['password']));
+ $common_name = $_GET['cn'];
+ $modeid = $_GET['modeid'];
+ $strictusercn = $_GET['strictcn'] == "false" ? false : true;
+} else {
+ /* read data from environment */
+ $username = getenv("username");
+ $password = getenv("password");
+ $common_name = getenv("common_name");
+}
+
+if (!$username || !$password) {
+ syslog(LOG_ERR, "invalid user authentication environment");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ return (-1);
+ }
+}
+
+/* Replaced by a sed with proper variables used below(ldap parameters). */
+//<template>
+
+if (file_exists("{$g['varetc_path']}/openvpn/{$modeid}.ca")) {
+ putenv("LDAPTLS_CACERT={$g['varetc_path']}/openvpn/{$modeid}.ca");
+ putenv("LDAPTLS_REQCERT=never");
+}
+
+$authenticated = false;
+
+if (($strictusercn === true) && ($common_name != $username)) {
+ syslog(LOG_WARNING, "Username does not match certificate common name ({$username} != {$common_name}), access denied.\n");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ return (1);
+ }
+}
+
+if (!is_array($authmodes)) {
+ syslog(LOG_WARNING, "No authentication server has been selected to authenticate against. Denying authentication for user {$username}");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ return (1);
+ }
+}
+
+$attributes = array();
+foreach ($authmodes as $authmode) {
+ $authcfg = auth_get_authserver($authmode);
+ if (!$authcfg && $authmode != "local") {
+ continue;
+ }
+
+ $authenticated = authenticate_user($username, $password, $authcfg, $attributes);
+ if ($authenticated == true) {
+ break;
+ }
+}
+
+if ($authenticated == false) {
+ syslog(LOG_WARNING, "user '{$username}' could not authenticate.\n");
+ if (isset($_GET['username'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ return (-1);
+ }
+}
+
+if (file_exists("/etc/inc/openvpn.attributes.php")) {
+ include_once("/etc/inc/openvpn.attributes.php");
+}
+
+$content = "";
+if (is_array($attributes['dns-servers'])) {
+ foreach ($attributes['dns-servers'] as $dnssrv) {
+ if (is_ipaddr($dnssrv)) {
+ $content .= "push \"dhcp-option DNS {$dnssrv}\"\n";
+ }
+ }
+}
+if (is_array($attributes['routes'])) {
+ foreach ($attributes['routes'] as $route) {
+ $content .= "push \"route {$route} vpn_gateway\"\n";
+ }
+}
+
+if (isset($attributes['framed_ip'])) {
+/* XXX: only use when TAP windows driver >= 8.2.x */
+/* if (isset($attributes['framed_mask'])) {
+ $content .= "topology subnet\n";
+ $content .= "ifconfig-push {$attributes['framed_ip']} {$attributes['framed_mask']}";
+ } else {
+*/
+ $content .= "topology net30\n";
+ $content .= "ifconfig-push {$attributes['framed_ip']} ". long2ip((ip2long($attributes['framed_ip']) + 1));
+// }
+}
+
+if (!empty($content)) {
+ @file_put_contents("{$g['tmp_path']}/{$username}", $content);
+}
+
+syslog(LOG_NOTICE, "user '{$username}' authenticated\n");
+closelog();
+
+if (isset($_GET['username'])) {
+ echo "OK";
+} else {
+ return (0);
+}
+
+?>
diff --git a/src/etc/inc/openvpn.inc b/src/etc/inc/openvpn.inc
new file mode 100644
index 0000000..d74aa3e
--- /dev/null
+++ b/src/etc/inc/openvpn.inc
@@ -0,0 +1,1589 @@
+<?php
+/*
+ openvpn.inc part of pfSense
+
+ Copyright (C) 2008 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2006 Fernando Lemos
+ All rights reserved.
+
+ This file was rewritten from scratch by Fernando Lemos but
+ *MIGHT* contain code previously written by:
+
+ Copyright (C) 2005 Peter Allgeyer <allgeyer_AT_web.de>
+ All rights reserved.
+
+ Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notices,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notices, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/openvpn /usr/bin/openssl /sbin/ifconfig
+ pfSense_MODULE: openvpn
+
+*/
+require_once('config.inc');
+require_once("certs.inc");
+require_once('pfsense-utils.inc');
+require_once("auth.inc");
+
+global $openvpn_prots;
+$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
+
+global $openvpn_dev_mode;
+$openvpn_dev_mode = array("tun", "tap");
+
+global $openvpn_verbosity_level;
+$openvpn_verbosity_level = array(
+ 0 => "none",
+ 1 => "default",
+ 2 => "2",
+ 3 => "3 (recommended)",
+ 4 => "4",
+ 5 => "5",
+ 6 => "6",
+ 7 => "7",
+ 8 => "8",
+ 9 => "9",
+ 10 => "10",
+ 11 => "11"
+);
+
+/*
+ * The User Auth mode below is disabled because
+ * OpenVPN erroneously requires that we provide
+ * a CA configuration parameter. In this mode,
+ * clients don't send a certificate so there is
+ * no need for a CA. If we require that admins
+ * provide one in the pfSense UI due to a bogus
+ * requirement imposed by OpenVPN, it could be
+ * considered very confusing ( I know I was ).
+ *
+ * -mgrooms
+ */
+
+global $openvpn_dh_lengths;
+$openvpn_dh_lengths = array(
+ 1024, 2048, 4096);
+
+global $openvpn_cert_depths;
+$openvpn_cert_depths = array(
+ 1 => "One (Client+Server)",
+ 2 => "Two (Client+Intermediate+Server)",
+ 3 => "Three (Client+2xIntermediate+Server)",
+ 4 => "Four (Client+3xIntermediate+Server)",
+ 5 => "Five (Client+4xIntermediate+Server)"
+);
+
+global $openvpn_server_modes;
+$openvpn_server_modes = array(
+ 'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
+ 'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
+ 'server_tls' => gettext("Remote Access ( SSL/TLS )"),
+ 'server_user' => gettext("Remote Access ( User Auth )"),
+ 'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
+
+global $openvpn_client_modes;
+$openvpn_client_modes = array(
+ 'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
+ 'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"));
+
+global $openvpn_compression_modes;
+$openvpn_compression_modes = array(
+ '' => gettext("No Preference"),
+ 'no' => gettext("Disabled - No Compression"),
+ 'adaptive' => gettext("Enabled with Adaptive Compression"),
+ 'yes' => gettext("Enabled without Adaptive Compression"));
+
+function openvpn_create_key() {
+
+ $fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
+ if (!$fp) {
+ return false;
+ }
+
+ $rslt = stream_get_contents($fp);
+ pclose($fp);
+
+ return $rslt;
+}
+
+function openvpn_create_dhparams($bits) {
+
+ $fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
+ if (!$fp) {
+ return false;
+ }
+
+ $rslt = stream_get_contents($fp);
+ pclose($fp);
+
+ return $rslt;
+}
+
+function openvpn_vpnid_used($vpnid) {
+ global $config;
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $settings) {
+ if ($vpnid == $settings['vpnid']) {
+ return true;
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as & $settings) {
+ if ($vpnid == $settings['vpnid']) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function openvpn_vpnid_next() {
+
+ $vpnid = 1;
+ while (openvpn_vpnid_used($vpnid)) {
+ $vpnid++;
+ }
+
+ return $vpnid;
+}
+
+function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
+ global $config;
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $settings) {
+ if (isset($settings['disable'])) {
+ continue;
+ }
+
+ if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
+ continue;
+ }
+
+ if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
+ ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
+ return $settings['vpnid'];
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as & $settings) {
+ if (isset($settings['disable'])) {
+ continue;
+ }
+
+ if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
+ continue;
+ }
+
+ if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
+ ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
+ return $settings['vpnid'];
+ }
+ }
+ }
+
+ return 0;
+}
+
+function openvpn_port_next($prot, $interface = "wan") {
+
+ $port = 1194;
+ while (openvpn_port_used($prot, $interface, $port)) {
+ $port++;
+ }
+ while (openvpn_port_used($prot, "any", $port)) {
+ $port++;
+ }
+
+ return $port;
+}
+
+function openvpn_get_cipherlist() {
+
+ $ciphers = array();
+ $cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
+ $cipher_lines = explode("\n", trim($cipher_out));
+ sort($cipher_lines);
+ foreach ($cipher_lines as $line) {
+ $words = explode(' ', $line);
+ $ciphers[$words[0]] = "{$words[0]} {$words[1]}";
+ }
+ $ciphers["none"] = gettext("None (No Encryption)");
+ return $ciphers;
+}
+
+function openvpn_get_digestlist() {
+
+ $digests = array();
+ $digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
+ $digest_lines = explode("\n", trim($digest_out));
+ sort($digest_lines);
+ foreach ($digest_lines as $line) {
+ $words = explode(' ', $line);
+ $digests[$words[0]] = "{$words[0]} {$words[1]}";
+ }
+ $digests["none"] = gettext("None (No Authentication)");
+ return $digests;
+}
+
+function openvpn_get_engines() {
+ $openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
+ exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
+ $openssl_engine_output = implode("\n", $openssl_engine_output);
+ $openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
+ $openssl_engine_output = explode("\n", $openssl_engine_output);
+
+ foreach ($openssl_engine_output as $oeo) {
+ $keep = true;
+ $details = explode("|", $oeo);
+ $engine = array_shift($details);
+ $linematch = array();
+ preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
+ foreach ($details as $dt) {
+ if (strpos($dt, "unavailable") !== FALSE) {
+ $keep = false;
+ }
+ if (strpos($dt, "available") !== FALSE) {
+ continue;
+ }
+ if (strpos($dt, "[") !== FALSE) {
+ $ciphers = trim($dt, "[]");
+ }
+ }
+ if (!empty($ciphers)) {
+ $ciphers = " - " . $ciphers;
+ }
+ if (strlen($ciphers) > 60) {
+ $ciphers = substr($ciphers, 0, 60) . " ... ";
+ }
+ if ($keep) {
+ $openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
+ }
+ }
+ return $openssl_engines;
+}
+
+function openvpn_validate_engine($engine) {
+ $engines = openvpn_get_engines();
+ return array_key_exists($engine, $engines);
+}
+
+function openvpn_validate_host($value, $name) {
+ $value = trim($value);
+ if (empty($value) || (!is_domain($value) && !is_ipaddr($value))) {
+ return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
+ }
+ return false;
+}
+
+function openvpn_validate_port($value, $name) {
+ $value = trim($value);
+ if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535)) {
+ return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
+ }
+ return false;
+}
+
+function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
+ $value = trim($value);
+ $error = false;
+ if (empty($value)) {
+ return false;
+ }
+ $networks = explode(',', $value);
+
+ if (!$multiple && (count($networks) > 1)) {
+ return sprintf(gettext("The field '%s' must contain a single valid %s CIDR range."), $name, $ipproto);
+ }
+
+ foreach ($networks as $network) {
+ if ($ipproto == "ipv4") {
+ $error = !openvpn_validate_cidr_ipv4($network);
+ } else {
+ $error = !openvpn_validate_cidr_ipv6($network);
+ }
+ if ($error) {
+ break;
+ }
+ }
+
+ if ($error) {
+ return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
+ } else {
+ return false;
+ }
+}
+
+function openvpn_validate_cidr_ipv4($value) {
+ $value = trim($value);
+ if (!empty($value)) {
+ list($ip, $mask) = explode('/', $value);
+ if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function openvpn_validate_cidr_ipv6($value) {
+ $value = trim($value);
+ if (!empty($value)) {
+ list($ipv6, $prefix) = explode('/', $value);
+ if (empty($prefix)) {
+ $prefix = "128";
+ }
+ if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function openvpn_add_dhcpopts(& $settings, & $conf) {
+
+ if (!empty($settings['dns_domain'])) {
+ $conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
+ }
+
+ if (!empty($settings['dns_server1'])) {
+ $conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
+ }
+ if (!empty($settings['dns_server2'])) {
+ $conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
+ }
+ if (!empty($settings['dns_server3'])) {
+ $conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
+ }
+ if (!empty($settings['dns_server4'])) {
+ $conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
+ }
+
+ if (!empty($settings['push_register_dns'])) {
+ $conf .= "push \"register-dns\"\n";
+ }
+
+ if (!empty($settings['ntp_server1'])) {
+ $conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
+ }
+ if (!empty($settings['ntp_server2'])) {
+ $conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
+ }
+
+ if ($settings['netbios_enable']) {
+
+ if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0)) {
+ $conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
+ }
+ if (!empty($settings['dhcp_nbtscope'])) {
+ $conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
+ }
+
+ if (!empty($settings['wins_server1'])) {
+ $conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
+ }
+ if (!empty($settings['wins_server2'])) {
+ $conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
+ }
+
+ if (!empty($settings['nbdd_server1'])) {
+ $conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
+ }
+ }
+
+ if ($settings['gwredir']) {
+ $conf .= "push \"redirect-gateway def1\"\n";
+ }
+}
+
+function openvpn_add_custom(& $settings, & $conf) {
+
+ if ($settings['custom_options']) {
+
+ $options = explode(';', $settings['custom_options']);
+
+ if (is_array($options)) {
+ foreach ($options as $option) {
+ $conf .= "$option\n";
+ }
+ } else {
+ $conf .= "{$settings['custom_options']}\n";
+ }
+ }
+}
+
+function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
+ global $g;
+
+ $fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
+ openvpn_create_dirs();
+ file_put_contents($fpath, base64_decode($data));
+ //chown($fpath, 'nobody');
+ //chgrp($fpath, 'nobody');
+ @chmod($fpath, 0600);
+
+ $conf .= "{$directive} {$fpath} {$opt}\n";
+}
+
+function openvpn_reconfigure($mode, $settings) {
+ global $g, $config;
+
+ if (empty($settings)) {
+ return;
+ }
+ if (isset($settings['disable'])) {
+ return;
+ }
+ openvpn_create_dirs();
+ /*
+ * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
+ * we use a vpnid number which is allocated for a particular client
+ * or server configuration. ( see openvpn_vpnid_next() )
+ */
+
+ $vpnid = $settings['vpnid'];
+ $mode_id = $mode.$vpnid;
+
+ if (isset($settings['dev_mode'])) {
+ $tunname = "{$settings['dev_mode']}{$vpnid}";
+ } else {
+ /* defaults to tun */
+ $tunname = "tun{$vpnid}";
+ $settings['dev_mode'] = "tun";
+ }
+
+ if ($mode == "server") {
+ $devname = "ovpns{$vpnid}";
+ } else {
+ $devname = "ovpnc{$vpnid}";
+ }
+
+ /* is our device already configured */
+ if (!does_interface_exist($devname)) {
+
+ /* create the tap device if required */
+ if (!file_exists("/dev/{$tunname}")) {
+ exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
+ }
+
+ /* rename the device */
+ mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
+
+ /* add the device to the openvpn group and make sure it's UP*/
+ mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " group openvpn up");
+
+ $ifname = convert_real_interface_to_friendly_interface_name($devname);
+ $grouptmp = link_interface_to_group($ifname);
+ if (!empty($grouptmp)) {
+ array_walk($grouptmp, 'interface_group_add_member');
+ }
+ unset($grouptmp, $ifname);
+ }
+
+ $pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
+ $proto = strtolower($settings['protocol']);
+ if (substr($settings['protocol'], 0, 3) == "TCP") {
+ $proto = "{$proto}-{$mode}";
+ }
+ $dev_mode = $settings['dev_mode'];
+ $cipher = $settings['crypto'];
+ // OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
+ $digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
+
+ $interface = get_failover_interface($settings['interface']);
+ // The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
+ $ipaddr = $settings['ipaddr'];
+
+ // If a specific ip address (VIP) is requested, use it.
+ // Otherwise, if a specific interface is requested, use it
+ // If "any" interface was selected, local directive will be omitted.
+ if (is_ipaddrv4($ipaddr)) {
+ $iface_ip = $ipaddr;
+ } else {
+ if ((!empty($interface)) && (strcmp($interface, "any"))) {
+ $iface_ip=get_interface_ip($interface);
+ }
+ }
+ if (is_ipaddrv6($ipaddr)) {
+ $iface_ipv6 = $ipaddr;
+ } else {
+ if ((!empty($interface)) && (strcmp($interface, "any"))) {
+ $iface_ipv6=get_interface_ipv6($interface);
+ }
+ }
+
+
+ $conf = "dev {$devname}\n";
+ if (isset($settings['verbosity_level'])) {
+ $conf .= "verb {$settings['verbosity_level']}\n";
+ }
+
+ $conf .= "dev-type {$settings['dev_mode']}\n";
+ switch ($settings['dev_mode']) {
+ case "tun":
+ if (!$settings['no_tun_ipv6']) {
+ $conf .= "tun-ipv6\n";
+ }
+ break;
+ }
+ $conf .= "dev-node /dev/{$tunname}\n";
+ $conf .= "writepid {$pfile}\n";
+ $conf .= "#user nobody\n";
+ $conf .= "#group nobody\n";
+ $conf .= "script-security 3\n";
+ $conf .= "daemon\n";
+ $conf .= "keepalive 10 60\n";
+ $conf .= "ping-timer-rem\n";
+ $conf .= "persist-tun\n";
+ $conf .= "persist-key\n";
+ $conf .= "proto {$proto}\n";
+ $conf .= "cipher {$cipher}\n";
+ $conf .= "auth {$digest}\n";
+ $conf .= "up /usr/local/sbin/ovpn-linkup\n";
+ $conf .= "down /usr/local/sbin/ovpn-linkdown\n";
+ if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
+ switch ($settings['mode']) {
+ case 'server_user':
+ case 'server_tls_user':
+ $conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
+ $conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
+ break;
+ }
+ }
+
+ /* Determine the local IP to use - and make sure it matches with the selected protocol. */
+ if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
+ $conf .= "local {$iface_ip}\n";
+ } elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
+ $conf .= "local {$iface_ipv6}\n";
+ }
+
+ if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
+ $conf .= "engine {$settings['engine']}\n";
+ }
+
+ // server specific settings
+ if ($mode == 'server') {
+
+ list($ip, $cidr) = explode('/', $settings['tunnel_network']);
+ list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
+ $mask = gen_subnet_mask($cidr);
+
+ // configure tls modes
+ switch ($settings['mode']) {
+ case 'p2p_tls':
+ case 'server_tls':
+ case 'server_user':
+ case 'server_tls_user':
+ $conf .= "tls-server\n";
+ break;
+ }
+
+ // configure p2p/server modes
+ switch ($settings['mode']) {
+ case 'p2p_tls':
+ // If the CIDR is less than a /30, OpenVPN will complain if you try to
+ // use the server directive. It works for a single client without it.
+ // See ticket #1417
+ if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
+ $conf .= "server {$ip} {$mask}\n";
+ $conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
+ if (is_ipaddr($ipv6)) {
+ $conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
+ }
+ }
+ case 'p2p_shared_key':
+ if (!empty($ip) && !empty($mask)) {
+ list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
+ if ($settings['dev_mode'] == 'tun') {
+ $conf .= "ifconfig {$ip1} {$ip2}\n";
+ } else {
+ $conf .= "ifconfig {$ip1} {$mask}\n";
+ }
+ }
+ if (!empty($ipv6) && !empty($prefix)) {
+ list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
+ if ($settings['dev_mode'] == 'tun') {
+ $conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
+ } else {
+ $conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
+ }
+ }
+ break;
+ case 'server_tls':
+ case 'server_user':
+ case 'server_tls_user':
+ if (!empty($ip) && !empty($mask)) {
+ $conf .= "server {$ip} {$mask}\n";
+ if (is_ipaddr($ipv6)) {
+ $conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
+ }
+ $conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
+ } else {
+ if ($settings['serverbridge_dhcp']) {
+ if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
+ $biface_ip=get_interface_ip($settings['serverbridge_interface']);
+ $biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
+ if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
+ $conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
+ $conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
+ } else {
+ $conf .= "mode server\n";
+ }
+ } else {
+ $conf .= "mode server\n";
+ }
+ }
+ }
+ break;
+ }
+
+ // configure user auth modes
+ switch ($settings['mode']) {
+ case 'server_user':
+ $conf .= "client-cert-not-required\n";
+ case 'server_tls_user':
+ /* username-as-common-name is not compatible with server-bridge */
+ if (stristr($conf, "server-bridge") === false) {
+ $conf .= "username-as-common-name\n";
+ }
+ if (!empty($settings['authmode'])) {
+ $strictusercn = "false";
+ if ($settings['strictusercn']) {
+ $strictusercn = "true";
+ }
+ $conf .= "auth-user-pass-verify \"/usr/local/sbin/ovpn_auth_verify user '{$settings['authmode']}' {$strictusercn} {$mode_id}\" via-env\n";
+ }
+ break;
+ }
+ if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls'))) {
+ $settings['cert_depth'] = 1;
+ }
+ if (is_numeric($settings['cert_depth'])) {
+ if (($mode == 'client') && empty($settings['certref'])) {
+ $cert = "";
+ } else {
+ $cert = lookup_cert($settings['certref']);
+ /* XXX: Seems not used at all! */
+ $servercn = urlencode(cert_get_cn($cert['crt']));
+ $conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']} \"\n";
+ }
+ }
+
+ // The local port to listen on
+ $conf .= "lport {$settings['local_port']}\n";
+
+ // The management port to listen on
+ // Use unix socket to overcome the problem on any type of server
+ $conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
+ //$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
+
+ if ($settings['maxclients']) {
+ $conf .= "max-clients {$settings['maxclients']}\n";
+ }
+
+ // Can we push routes
+ if ($settings['local_network']) {
+ $conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
+ }
+ if ($settings['local_networkv6']) {
+ $conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
+ }
+
+ switch ($settings['mode']) {
+ case 'server_tls':
+ case 'server_user':
+ case 'server_tls_user':
+ // Configure client dhcp options
+ openvpn_add_dhcpopts($settings, $conf);
+ if ($settings['client2client']) {
+ $conf .= "client-to-client\n";
+ }
+ break;
+ }
+ if (isset($settings['duplicate_cn'])) {
+ $conf .= "duplicate-cn\n";
+ }
+ }
+
+ // client specific settings
+
+ if ($mode == 'client') {
+
+ // configure p2p mode
+ switch ($settings['mode']) {
+ case 'p2p_tls':
+ $conf .= "tls-client\n";
+ case 'shared_key':
+ $conf .= "client\n";
+ break;
+ }
+
+ // If there is no bind option at all (ip and/or port), add "nobind" directive
+ // Otherwise, use the local port if defined, failing that, use lport 0 to
+ // ensure a random source port.
+ if ((empty($iface_ip)) && (!$settings['local_port'])) {
+ $conf .= "nobind\n";
+ } elseif ($settings['local_port']) {
+ $conf .= "lport {$settings['local_port']}\n";
+ } else {
+ $conf .= "lport 0\n";
+ }
+
+ // Use unix socket to overcome the problem on any type of server
+ $conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
+
+ // The remote server
+ $conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
+
+ if (!empty($settings['use_shaper'])) {
+ $conf .= "shaper {$settings['use_shaper']}\n";
+ }
+
+ if (!empty($settings['tunnel_network'])) {
+ list($ip, $mask) = explode('/', $settings['tunnel_network']);
+ $mask = gen_subnet_mask($mask);
+ list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
+ if ($settings['dev_mode'] == 'tun') {
+ $conf .= "ifconfig {$ip2} {$ip1}\n";
+ } else {
+ $conf .= "ifconfig {$ip2} {$mask}\n";
+ }
+ }
+
+ if (!empty($settings['tunnel_networkv6'])) {
+ list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
+ list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
+ if ($settings['dev_mode'] == 'tun') {
+ $conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
+ } else {
+ $conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
+ }
+ }
+
+ if ($settings['auth_user'] || $settings['auth_pass']) {
+ $up_file = "{$g['varetc_path']}/openvpn/{$mode_id}.up";
+ $conf .= "auth-user-pass {$up_file}\n";
+ if ($settings['auth_user']) {
+ $userpass = "{$settings['auth_user']}\n";
+ } else {
+ $userpass = "";
+ }
+ if ($settings['auth_pass']) {
+ $userpass .= "{$settings['auth_pass']}\n";
+ }
+ // If only auth_pass is given, then it acts like a user name and we put a blank line where pass would normally go.
+ if (!($settings['auth_user'] && $settings['auth_pass'])) {
+ $userpass .= "\n";
+ }
+ file_put_contents($up_file, $userpass);
+ }
+
+ if ($settings['proxy_addr']) {
+ $conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
+ if ($settings['proxy_authtype'] != "none") {
+ $conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
+ $proxypas = "{$settings['proxy_user']}\n";
+ $proxypas .= "{$settings['proxy_passwd']}\n";
+ file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
+ }
+ $conf .= " \n";
+ }
+ }
+
+ // Add a remote network route if set, and only for p2p modes.
+ if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
+ $conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
+ }
+ // Add a remote network route if set, and only for p2p modes.
+ if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
+ $conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
+ }
+
+ // Write the settings for the keys
+ switch ($settings['mode']) {
+ case 'p2p_shared_key':
+ openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
+ break;
+ case 'p2p_tls':
+ case 'server_tls':
+ case 'server_tls_user':
+ case 'server_user':
+ $ca = lookup_ca($settings['caref']);
+ openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
+
+ if (!empty($settings['certref'])) {
+ $cert = lookup_cert($settings['certref']);
+ openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
+ openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
+ }
+ if ($mode == 'server') {
+ $conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
+ }
+ if (!empty($settings['crlref'])) {
+ $crl = lookup_crl($settings['crlref']);
+ crl_update($crl);
+ openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
+ }
+ if ($settings['tls']) {
+ if ($mode == "server") {
+ $tlsopt = 0;
+ } else {
+ $tlsopt = 1;
+ }
+ openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
+ }
+ break;
+ }
+
+ if (!empty($settings['compression'])) {
+ $conf .= "comp-lzo {$settings['compression']}\n";
+ }
+
+ if ($settings['passtos']) {
+ $conf .= "passtos\n";
+ }
+
+ if ($settings['resolve_retry']) {
+ $conf .= "resolv-retry infinite\n";
+ } else if ($mode == 'clie} nt') {
+ $conf .= "resolv-retry infinite\n";
+ }
+
+ if ($settings['dynamic_ip']) {
+ $conf .= "persist-remote-ip\n";
+ $conf .= "float\n";
+ }
+
+ if ($settings['topology_subnet']) {
+ $conf .= "topology subnet\n";
+ }
+
+ // New client features
+ if ($mode == "client") {
+ // Dont pull routes checkbox
+ if ($settings['route_no_pull']) {
+ $conf .= "route-nopull\n";
+ }
+
+ // Dont add/remove routes checkbox
+ if ($settings['route_no_exec']) {
+ $conf .= "route-noexec\n";
+ }
+ }
+
+ openvpn_add_custom($settings, $conf);
+
+ openvpn_create_dirs();
+ $fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
+ file_put_contents($fpath, $conf);
+ unset($conf);
+ $fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
+ file_put_contents($fpath, $interface);
+ //chown($fpath, 'nobody');
+ //chgrp($fpath, 'nobody');
+ @chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
+ @chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
+ @chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
+ @chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
+ @chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
+}
+
+function openvpn_restart($mode, $settings) {
+ global $g, $config;
+
+ $vpnid = $settings['vpnid'];
+ $mode_id = $mode.$vpnid;
+
+ /* kill the process if running */
+ $pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
+ if (file_exists($pfile)) {
+
+ /* read the pid file */
+ $pid = rtrim(file_get_contents($pfile));
+ unlink($pfile);
+
+ /* send a term signal to the process */
+ posix_kill($pid, SIGTERM);
+
+ /* wait until the process exits, or timeout and kill it */
+ $i = 0;
+ while (posix_kill($pid, 0)) {
+ usleep(250000);
+ if ($i > 10) {
+ log_error("OpenVPN ID $mode_id PID $pid still running, killing.");
+ posix_kill($pid, SIGKILL);
+ usleep(500000);
+ }
+ $i++;
+ }
+ }
+
+ if (isset($settings['disable'])) {
+ return;
+ }
+
+ /* Do not start a client if we are a CARP backup on this vip! */
+ if (($mode == "client") && (strstr($settings['interface'], "_vip") && get_carp_interface_status($settings['interface']) != "MASTER")) {
+ return;
+ }
+
+ /* Check if client is bound to a gateway group */
+ $a_groups = return_gateway_groups_array();
+ if (is_array($a_groups[$settings['interface']])) {
+ /* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
+ if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) != "MASTER")) {
+ return;
+ }
+ }
+
+ /* start the new process */
+ $fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
+ openvpn_clear_route($mode, $settings);
+ mwexec_bg("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
+
+ if (!platform_booting()) {
+ send_event("filter reload");
+ }
+}
+
+function openvpn_delete($mode, & $settings) {
+ global $g, $config;
+
+ $vpnid = $settings['vpnid'];
+ $mode_id = $mode.$vpnid;
+
+ if (isset($settings['dev_mode'])) {
+ $tunname = "{$settings['dev_mode']}{$vpnid}";
+ } else {
+ /* defaults to tun */
+ $tunname = "tun{$vpnid}";
+ }
+
+ if ($mode == "server") {
+ $devname = "ovpns{$vpnid}";
+ } else {
+ $devname = "ovpnc{$vpnid}";
+ }
+
+ /* kill the process if running */
+ $pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
+ if (file_exists($pfile)) {
+
+ /* read the pid file */
+ $pid = trim(file_get_contents($pfile));
+ unlink($pfile);
+
+ /* send a term signal to the process */
+ posix_kill($pid, SIGTERM);
+ }
+
+ /* remove the device from the openvpn group */
+ mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
+
+ /* restore the original adapter name */
+ mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
+
+ /* remove the configuration files */
+ @array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
+}
+
+function openvpn_cleanup_csc($common_name) {
+ global $g, $config;
+ if (empty($common_name)) {
+ return;
+ }
+ $fpath = "{$g['varetc_path']}/openvpn-csc/" . basename($common_name);
+ if (is_file($fpath)) {
+ unlink_if_exists($fpath);
+ }
+ return;
+}
+
+function openvpn_resync_csc(& $settings) {
+ global $g, $config;
+
+ $fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
+
+ if (isset($settings['disable'])) {
+ unlink_if_exists($fpath);
+ return;
+ }
+ openvpn_create_dirs();
+
+ $conf = '';
+ if ($settings['block']) {
+ $conf .= "disable\n";
+ }
+
+ if ($settings['push_reset']) {
+ $conf .= "push-reset\n";
+ }
+
+ if (!empty($settings['tunnel_network'])) {
+ list($ip, $mask) = explode('/', $settings['tunnel_network']);
+ $baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
+ $serverip = long2ip32($baselong + 1);
+ $clientip = long2ip32($baselong + 2);
+ /* Because this is being pushed, the order from the client's point of view. */
+ if ($settings['dev_mode'] != 'tap') {
+ $conf .= "ifconfig-push {$clientip} {$serverip}\n";
+ } else {
+ $conf .= "ifconfig-push {$clientip} {$mask}\n";
+ }
+ }
+
+ if ($settings['local_network']) {
+ $conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
+ }
+ if ($settings['local_networkv6']) {
+ $conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
+ }
+
+ // Add a remote network iroute if set
+ if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
+ $conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
+ }
+ // Add a remote network iroute if set
+ if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
+ $conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
+ }
+
+ openvpn_add_dhcpopts($settings, $conf);
+
+ if ($settings['gwredir']) {
+ $conf .= "push \"redirect-gateway def1\"\n";
+ }
+
+ openvpn_add_custom($settings, $conf);
+
+ file_put_contents($fpath, $conf);
+ chown($fpath, 'nobody');
+ chgrp($fpath, 'nobody');
+}
+
+function openvpn_delete_csc(& $settings) {
+ global $g, $config;
+
+ $fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
+ unlink_if_exists($fpath);
+}
+
+// Resync the configuration and restart the VPN
+function openvpn_resync($mode, $settings) {
+ openvpn_reconfigure($mode, $settings);
+ openvpn_restart($mode, $settings);
+}
+
+// Resync and restart all VPNs
+function openvpn_resync_all($interface = "") {
+ global $g, $config;
+
+ openvpn_create_dirs();
+
+ if (!is_array($config['openvpn'])) {
+ $config['openvpn'] = array();
+ }
+
+/*
+ if (!$config['openvpn']['dh-parameters']) {
+ echo "Configuring OpenVPN Parameters ...\n";
+ $dh_parameters = openvpn_create_dhparams(1024);
+ $dh_parameters = base64_encode($dh_parameters);
+ $config['openvpn']['dh-parameters'] = $dh_parameters;
+ write_config("OpenVPN DH parameters");
+ }
+
+ $path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
+ if (!file_exists($path_ovdh)) {
+ $dh_parameters = $config['openvpn']['dh-parameters'];
+ $dh_parameters = base64_decode($dh_parameters);
+ file_put_contents($path_ovdh, $dh_parameters);
+ }
+*/
+ if ($interface <> "") {
+ log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
+ } else {
+ log_error("Resyncing OpenVPN instances.");
+ }
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $settings) {
+ if ($interface <> "" && $interface != $settings['interface']) {
+ continue;
+ }
+ openvpn_resync('server', $settings);
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as & $settings) {
+ if ($interface <> "" && $interface != $settings['interface']) {
+ continue;
+ }
+ openvpn_resync('client', $settings);
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-csc'])) {
+ foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
+ openvpn_resync_csc($settings);
+ }
+ }
+
+}
+
+// Resync and restart all VPNs using a gateway group.
+function openvpn_resync_gwgroup($gwgroupname = "") {
+ global $g, $config;
+
+ if ($gwgroupname <> "") {
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $settings) {
+ if ($gwgroupname == $settings['interface']) {
+ log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
+ openvpn_resync('server', $settings);
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as & $settings) {
+ if ($gwgroupname == $settings['interface']) {
+ log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
+ openvpn_resync('client', $settings);
+ }
+ }
+ }
+
+ // Note: no need to resysnc Client Specific (csc) here, as changes to the OpenVPN real interface do not effect these.
+
+ } else {
+ log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
+ }
+}
+
+function openvpn_get_active_servers($type="multipoint") {
+ global $config, $g;
+
+ $servers = array();
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as & $settings) {
+ if (empty($settings) || isset($settings['disable'])) {
+ continue;
+ }
+
+ $prot = $settings['protocol'];
+ $port = $settings['local_port'];
+
+ $server = array();
+ $server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
+ $server['mode'] = $settings['mode'];
+ if ($settings['description']) {
+ $server['name'] = "{$settings['description']} {$prot}:{$port}";
+ } else {
+ $server['name'] = "Server {$prot}:{$port}";
+ }
+ $server['conns'] = array();
+ $server['vpnid'] = $settings['vpnid'];
+ $server['mgmt'] = "server{$server['vpnid']}";
+ $socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
+ list($tn, $sm) = explode('/', $settings['tunnel_network']);
+
+ if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30)) && ($type == "p2p")) {
+ $servers[] = openvpn_get_client_status($server, $socket);
+ } elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30)) {
+ $servers[] = openvpn_get_server_status($server, $socket);
+ }
+ }
+ }
+ return $servers;
+}
+
+function openvpn_get_server_status($server, $socket) {
+ $errval;
+ $errstr;
+ $fp = @stream_socket_client($socket, $errval, $errstr, 1);
+ if ($fp) {
+ stream_set_timeout($fp, 1);
+
+ /* send our status request */
+ fputs($fp, "status 2\n");
+
+ /* recv all response lines */
+ while (!feof($fp)) {
+
+ /* read the next line */
+ $line = fgets($fp, 1024);
+
+ $info = stream_get_meta_data($fp);
+ if ($info['timed_out']) {
+ break;
+ }
+
+ /* parse header list line */
+ if (strstr($line, "HEADER")) {
+ continue;
+ }
+
+ /* parse end of output line */
+ if (strstr($line, "END") || strstr($line, "ERROR")) {
+ break;
+ }
+
+ /* parse client list line */
+ if (strstr($line, "CLIENT_LIST")) {
+ $list = explode(",", $line);
+ $conn = array();
+ $conn['common_name'] = $list[1];
+ $conn['remote_host'] = $list[2];
+ $conn['virtual_addr'] = $list[3];
+ $conn['bytes_recv'] = $list[4];
+ $conn['bytes_sent'] = $list[5];
+ $conn['connect_time'] = $list[6];
+ $server['conns'][] = $conn;
+ }
+ /* parse routing table lines */
+ if (strstr($line, "ROUTING_TABLE")) {
+ $list = explode(",", $line);
+ $conn = array();
+ $conn['virtual_addr'] = $list[1];
+ $conn['common_name'] = $list[2];
+ $conn['remote_host'] = $list[3];
+ $conn['last_time'] = $list[4];
+ $server['routes'][] = $conn;
+ }
+ }
+
+ /* cleanup */
+ fclose($fp);
+ } else {
+ $conn = array();
+ $conn['common_name'] = "[error]";
+ $conn['remote_host'] = "Unable to contact daemon";
+ $conn['virtual_addr'] = "Service not running?";
+ $conn['bytes_recv'] = 0;
+ $conn['bytes_sent'] = 0;
+ $conn['connect_time'] = 0;
+ $server['conns'][] = $conn;
+ }
+ return $server;
+}
+
+function openvpn_get_active_clients() {
+ global $config, $g;
+
+ $clients = array();
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as & $settings) {
+
+ if (empty($settings) || isset($settings['disable'])) {
+ continue;
+ }
+
+ $prot = $settings['protocol'];
+ $port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
+
+ $client = array();
+ $client['port'] = $settings['local_port'];
+ if ($settings['description']) {
+ $client['name'] = "{$settings['description']} {$prot}{$port}";
+ } else {
+ $client['name'] = "Client {$prot}{$port}";
+ }
+
+ $client['vpnid'] = $settings['vpnid'];
+ $client['mgmt'] = "client{$client['vpnid']}";
+ $socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
+ $client['status'] = "down";
+
+ $clients[] = openvpn_get_client_status($client, $socket);
+ }
+ }
+ return $clients;
+}
+
+function openvpn_get_client_status($client, $socket) {
+ $errval;
+ $errstr;
+ $fp = @stream_socket_client($socket, $errval, $errstr, 1);
+ if ($fp) {
+ stream_set_timeout($fp, 1);
+ /* send our status request */
+ fputs($fp, "state 1\n");
+
+ /* recv all response lines */
+ while (!feof($fp)) {
+ /* read the next line */
+ $line = fgets($fp, 1024);
+
+ $info = stream_get_meta_data($fp);
+ if ($info['timed_out']) {
+ break;
+ }
+
+ /* Get the client state */
+ if (strstr($line, "CONNECTED")) {
+ $client['status'] = "up";
+ $list = explode(",", $line);
+
+ $client['connect_time'] = date("D M j G:i:s Y", $list[0]);
+ $client['virtual_addr'] = $list[3];
+ $client['remote_host'] = $list[4];
+ }
+ if (strstr($line, "CONNECTING")) {
+ $client['status'] = "connecting";
+ }
+ if (strstr($line, "ASSIGN_IP")) {
+ $client['status'] = "waiting";
+ $list = explode(",", $line);
+
+ $client['connect_time'] = date("D M j G:i:s Y", $list[0]);
+ $client['virtual_addr'] = $list[3];
+ }
+ if (strstr($line, "RECONNECTING")) {
+ $client['status'] = "reconnecting";
+ $list = explode(",", $line);
+
+ $client['connect_time'] = date("D M j G:i:s Y", $list[0]);
+ $client['status'] .= "; " . $list[2];
+ }
+ /* parse end of output line */
+ if (strstr($line, "END") || strstr($line, "ERROR")) {
+ break;
+ }
+ }
+
+ /* If up, get read/write stats */
+ if (strcmp($client['status'], "up") == 0) {
+ fputs($fp, "status 2\n");
+ /* recv all response lines */
+ while (!feof($fp)) {
+ /* read the next line */
+ $line = fgets($fp, 1024);
+
+ $info = stream_get_meta_data($fp);
+ if ($info['timed_out']) {
+ break;
+ }
+
+ if (strstr($line, "TCP/UDP read bytes")) {
+ $list = explode(",", $line);
+ $client['bytes_recv'] = $list[1];
+ }
+
+ if (strstr($line, "TCP/UDP write bytes")) {
+ $list = explode(",", $line);
+ $client['bytes_sent'] = $list[1];
+ }
+
+ /* parse end of output line */
+ if (strstr($line, "END")) {
+ break;
+ }
+ }
+ }
+
+ fclose($fp);
+
+ } else {
+ $DisplayNote=true;
+ $client['remote_host'] = "Unable to contact daemon";
+ $client['virtual_addr'] = "Service not running?";
+ $client['bytes_recv'] = 0;
+ $client['bytes_sent'] = 0;
+ $client['connect_time'] = 0;
+ }
+ return $client;
+}
+
+function openvpn_refresh_crls() {
+ global $g, $config;
+
+ openvpn_create_dirs();
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $settings) {
+ if (empty($settings)) {
+ continue;
+ }
+ if (isset($settings['disable'])) {
+ continue;
+ }
+ // Write the settings for the keys
+ switch ($settings['mode']) {
+ case 'p2p_tls':
+ case 'server_tls':
+ case 'server_tls_user':
+ case 'server_user':
+ if (!empty($settings['crlref'])) {
+ $crl = lookup_crl($settings['crlref']);
+ crl_update($crl);
+ $fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
+ file_put_contents($fpath, base64_decode($crl['text']));
+ @chmod($fpath, 0644);
+ }
+ break;
+ }
+ }
+ }
+}
+
+function openvpn_create_dirs() {
+ global $g;
+ if (!is_dir("{$g['varetc_path']}/openvpn")) {
+ safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
+ }
+ if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
+ safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
+ }
+}
+
+function openvpn_get_interface_ip($ip, $mask) {
+ $baselong = ip2long32($ip) & ip2long($mask);
+ $ip1 = long2ip32($baselong + 1);
+ $ip2 = long2ip32($baselong + 2);
+ return array($ip1, $ip2);
+}
+
+function openvpn_get_interface_ipv6($ipv6, $prefix) {
+ $basev6 = gen_subnetv6($ipv6, $prefix);
+ // Is there a better way to do this math?
+ $ipv6_arr = explode(':', $basev6);
+ $last = hexdec(array_pop($ipv6_arr));
+ $ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
+ $ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
+ return array($ipv6_1, $ipv6_2);
+}
+
+function openvpn_clear_route($mode, $settings) {
+ if (empty($settings['tunnel_network'])) {
+ return;
+ }
+ list($ip, $cidr) = explode('/', $settings['tunnel_network']);
+ $mask = gen_subnet_mask($cidr);
+ $clear_route = false;
+
+ switch ($settings['mode']) {
+ case 'shared_key':
+ $clear_route = true;
+ break;
+ case 'p2p_tls':
+ case 'p2p_shared_key':
+ if ($cidr == 30) {
+ $clear_route = true;
+ }
+ break;
+ }
+
+ if ($clear_route && !empty($ip) && !empty($mask)) {
+ list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
+ $ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
+ /* XXX: Family for route? */
+ mwexec("/sbin/route -q delete {$ip_to_clear}");
+ }
+}
+
+function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
+ $routes = "";
+ if (empty($value)) {
+ return "";
+ }
+ $networks = explode(',', $value);
+
+ foreach ($networks as $network) {
+ if ($ipproto == "ipv4") {
+ $route = openvpn_gen_route_ipv4($network, $iroute);
+ } else {
+ $route = openvpn_gen_route_ipv6($network, $iroute);
+ }
+
+ if ($push) {
+ $routes .= "push \"{$route}\"\n";
+ } else {
+ $routes .= "{$route}\n";
+ }
+ }
+ return $routes;
+}
+
+function openvpn_gen_route_ipv4($network, $iroute = false) {
+ $i = ($iroute) ? "i" : "";
+ list($ip, $mask) = explode('/', trim($network));
+ $mask = gen_subnet_mask($mask);
+ return "{$i}route $ip $mask";
+}
+
+function openvpn_gen_route_ipv6($network, $iroute = false) {
+ $i = ($iroute) ? "i" : "";
+ list($ipv6, $prefix) = explode('/', trim($network));
+ if (empty($prefix)) {
+ $prefix = "128";
+ }
+ return "{$i}route-ipv6 ${ipv6}/${prefix}";
+}
+
+function openvpn_get_settings($mode, $vpnid) {
+ global $config;
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $settings) {
+ if (isset($settings['disable'])) {
+ continue;
+ }
+
+ if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
+ return $settings;
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as $settings) {
+ if (isset($settings['disable'])) {
+ continue;
+ }
+
+ if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
+ return $settings;
+ }
+ }
+ }
+
+ return array();
+}
+
+function openvpn_restart_by_vpnid($mode, $vpnid) {
+ $settings = openvpn_get_settings($mode, $vpnid);
+ openvpn_restart($mode, $settings);
+}
+
+?>
diff --git a/src/etc/inc/openvpn.tls-verify.php b/src/etc/inc/openvpn.tls-verify.php
new file mode 100644
index 0000000..9e21342
--- /dev/null
+++ b/src/etc/inc/openvpn.tls-verify.php
@@ -0,0 +1,97 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ openvpn.tls-verify.php
+
+ Copyright (C) 2011 Jim Pingle
+ Copyright (C) 2013-2015 Electric Sheep Fencing, LP
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+/*
+ pfSense_BUILDER_BINARIES:
+ pfSense_MODULE: openvpn
+*/
+/*
+ * OpenVPN calls this script to validate a certificate
+ * This script is called ONCE per DEPTH of the certificate chain
+ * Normal operation would have two runs - one for the server certificate
+ * and one for the client certificate. Beyond that, you're dealing with
+ * intermediates.
+ */
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("interfaces.inc");
+
+openlog("openvpn", LOG_ODELAY, LOG_AUTH);
+
+/* read data from command line */
+if (isset($_GET['certdepth'])) {
+ $cert_depth = $_GET['certdepth'];
+ $cert_subject = urldecode($_GET['certsubject']);
+ $allowed_depth = $_GET['depth'];
+ $server_cn = $_GET['servercn'];
+} else {
+ $cert_depth = intval($argv[1]);
+ $cert_subject = $argv[2];
+}
+
+/* Reserved for future use in case we decide to verify CNs and such as well
+$subj = explode("/", $cert_subject);
+foreach ($subj at $s) {
+ list($n, $v) = explode("=", $s);
+ if ($n == "CN") {
+ $common_name = $v;
+ }
+}
+*/
+
+/* Replaced by sed with proper variables used below ( $server_cn and $allowed_depth ). */
+//<template>
+
+if (isset($allowed_depth) && ($cert_depth > $allowed_depth)) {
+ syslog(LOG_WARNING, "Certificate depth {$cert_depth} exceeded max allowed depth of {$allowed_depth}.\n");
+ if (isset($_GET['certdepth'])) {
+ echo "FAILED";
+ closelog();
+ return;
+ } else {
+ closelog();
+ exit(1);
+ }
+}
+
+// Debug
+//syslog(LOG_WARNING, "Found certificate {$argv[2]} with depth {$cert_depth}\n");
+
+closelog();
+if (isset($_GET['certdepth'])) {
+ echo "OK";
+} else {
+ exit(0);
+}
+
+?>
diff --git a/src/etc/inc/pfsense-utils.inc b/src/etc/inc/pfsense-utils.inc
new file mode 100644
index 0000000..91988c7
--- /dev/null
+++ b/src/etc/inc/pfsense-utils.inc
@@ -0,0 +1,3211 @@
+<?php
+/****h* pfSense/pfsense-utils
+ NAME
+ pfsense-utils.inc - Utilities specific to pfSense
+ DESCRIPTION
+ This include contains various pfSense specific functions.
+ HISTORY
+ $Id$
+
+ Copyright (C) 2004-2007 Scott Ullrich (sullrich@gmail.com)
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /sbin/ifconfig /sbin/pfctl /usr/local/bin/php-cgi /usr/bin/netstat
+ pfSense_BUILDER_BINARIES: /bin/df /usr/bin/grep /usr/bin/awk /bin/rm /usr/sbin/pwd_mkdb /usr/bin/host
+ pfSense_BUILDER_BINARIES: /sbin/kldload
+ pfSense_MODULE: utils
+*/
+
+/****f* pfsense-utils/have_natpfruleint_access
+ * NAME
+ * have_natpfruleint_access
+ * INPUTS
+ * none
+ * RESULT
+ * returns true if user has access to edit a specific firewall nat port forward interface
+ ******/
+function have_natpfruleint_access($if) {
+ $security_url = "firewall_nat_edit.php?if=". strtolower($if);
+ if (isAllowedPage($security_url, $allowed)) {
+ return true;
+ }
+ return false;
+}
+
+/****f* pfsense-utils/have_ruleint_access
+ * NAME
+ * have_ruleint_access
+ * INPUTS
+ * none
+ * RESULT
+ * returns true if user has access to edit a specific firewall interface
+ ******/
+function have_ruleint_access($if) {
+ $security_url = "firewall_rules.php?if=". strtolower($if);
+ if (isAllowedPage($security_url)) {
+ return true;
+ }
+ return false;
+}
+
+/****f* pfsense-utils/does_url_exist
+ * NAME
+ * does_url_exist
+ * INPUTS
+ * none
+ * RESULT
+ * returns true if a url is available
+ ******/
+function does_url_exist($url) {
+ $fd = fopen("$url", "r");
+ if ($fd) {
+ fclose($fd);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/****f* pfsense-utils/is_private_ip
+ * NAME
+ * is_private_ip
+ * INPUTS
+ * none
+ * RESULT
+ * returns true if an ip address is in a private range
+ ******/
+function is_private_ip($iptocheck) {
+ $isprivate = false;
+ $ip_private_list = array(
+ "10.0.0.0/8",
+ "100.64.0.0/10",
+ "172.16.0.0/12",
+ "192.168.0.0/16",
+ );
+ foreach ($ip_private_list as $private) {
+ if (ip_in_subnet($iptocheck, $private) == true) {
+ $isprivate = true;
+ }
+ }
+ return $isprivate;
+}
+
+/****f* pfsense-utils/get_tmp_file
+ * NAME
+ * get_tmp_file
+ * INPUTS
+ * none
+ * RESULT
+ * returns a temporary filename
+ ******/
+function get_tmp_file() {
+ global $g;
+ return "{$g['tmp_path']}/tmp-" . time();
+}
+
+/****f* pfsense-utils/get_dns_servers
+ * NAME
+ * get_dns_servers - get system dns servers
+ * INPUTS
+ * none
+ * RESULT
+ * $dns_servers - an array of the dns servers
+ ******/
+function get_dns_servers() {
+ $dns_servers = array();
+ if (file_exists("/etc/resolv.conf")) {
+ $dns_s = file("/etc/resolv.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ }
+ if (is_array($dns_s)) {
+ foreach ($dns_s as $dns) {
+ $matches = "";
+ if (preg_match("/nameserver (.*)/", $dns, $matches)) {
+ $dns_servers[] = $matches[1];
+ }
+ }
+ }
+ return array_unique($dns_servers);
+}
+
+function hardware_offloading_applyflags($iface) {
+ global $config;
+
+ $flags_on = 0;
+ $flags_off = 0;
+ $options = pfSense_get_interface_addresses($iface);
+
+ if (isset($config['system']['disablechecksumoffloading'])) {
+ if (isset($options['encaps']['txcsum'])) {
+ $flags_off |= IFCAP_TXCSUM;
+ }
+ if (isset($options['encaps']['rxcsum'])) {
+ $flags_off |= IFCAP_RXCSUM;
+ }
+ } else {
+ if (isset($options['caps']['txcsum'])) {
+ $flags_on |= IFCAP_TXCSUM;
+ }
+ if (isset($options['caps']['rxcsum'])) {
+ $flags_on |= IFCAP_RXCSUM;
+ }
+ }
+
+ if (isset($config['system']['disablesegmentationoffloading'])) {
+ $flags_off |= IFCAP_TSO;
+ } else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
+ $flags_on |= IFCAP_TSO;
+ }
+
+ if (isset($config['system']['disablelargereceiveoffloading'])) {
+ $flags_off |= IFCAP_LRO;
+ } else if (isset($options['caps']['lro'])) {
+ $flags_on |= IFCAP_LRO;
+ }
+
+ /* if the NIC supports polling *AND* it is enabled in the GUI */
+ if (!isset($config['system']['polling'])) {
+ $flags_off |= IFCAP_POLLING;
+ } else if (isset($options['caps']['polling'])) {
+ $flags_on |= IFCAP_POLLING;
+ }
+
+ pfSense_interface_capabilities($iface, -$flags_off);
+ pfSense_interface_capabilities($iface, $flags_on);
+}
+
+/****f* pfsense-utils/enable_hardware_offloading
+ * NAME
+ * enable_hardware_offloading - Enable a NIC's supported hardware features.
+ * INPUTS
+ * $interface - string containing the physical interface to work on.
+ * RESULT
+ * null
+ * NOTES
+ * This function only supports the fxp driver's loadable microcode.
+ ******/
+function enable_hardware_offloading($interface) {
+ global $g, $config;
+
+ $int = get_real_interface($interface);
+ if (empty($int)) {
+ return;
+ }
+
+ if (!isset($config['system']['do_not_use_nic_microcode'])) {
+ /* translate wan, lan, opt -> real interface if needed */
+ $int_family = preg_split("/[0-9]+/", $int);
+ $supported_ints = array('fxp');
+ if (in_array($int_family, $supported_ints)) {
+ if (does_interface_exist($int)) {
+ pfSense_interface_flags($int, IFF_LINK0);
+ }
+ }
+ }
+
+ /* This is mostly for vlans and ppp types */
+ $realhwif = get_parent_interface($interface);
+ if ($realhwif[0] == $int) {
+ hardware_offloading_applyflags($int);
+ } else {
+ hardware_offloading_applyflags($realhwif[0]);
+ hardware_offloading_applyflags($int);
+ }
+}
+
+/****f* pfsense-utils/interface_supports_polling
+ * NAME
+ * checks to see if an interface supports polling according to man polling
+ * INPUTS
+ *
+ * RESULT
+ * true or false
+ * NOTES
+ *
+ ******/
+function interface_supports_polling($iface) {
+ $opts = pfSense_get_interface_addresses($iface);
+ if (is_array($opts) && isset($opts['caps']['polling'])) {
+ return true;
+ }
+
+ return false;
+}
+
+/****f* pfsense-utils/is_alias_inuse
+ * NAME
+ * checks to see if an alias is currently in use by a rule
+ * INPUTS
+ *
+ * RESULT
+ * true or false
+ * NOTES
+ *
+ ******/
+function is_alias_inuse($alias) {
+ global $g, $config;
+
+ if ($alias == "") {
+ return false;
+ }
+ /* loop through firewall rules looking for alias in use */
+ if (is_array($config['filter']['rule'])) {
+ foreach ($config['filter']['rule'] as $rule) {
+ if ($rule['source']['address']) {
+ if ($rule['source']['address'] == $alias) {
+ return true;
+ }
+ }
+ if ($rule['destination']['address']) {
+ if ($rule['destination']['address'] == $alias) {
+ return true;
+ }
+ }
+ }
+ }
+ /* loop through nat rules looking for alias in use */
+ if (is_array($config['nat']['rule'])) {
+ foreach ($config['nat']['rule'] as $rule) {
+ if ($rule['target'] && $rule['target'] == $alias) {
+ return true;
+ }
+ if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
+ return true;
+ }
+ if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/****f* pfsense-utils/is_schedule_inuse
+ * NAME
+ * checks to see if a schedule is currently in use by a rule
+ * INPUTS
+ *
+ * RESULT
+ * true or false
+ * NOTES
+ *
+ ******/
+function is_schedule_inuse($schedule) {
+ global $g, $config;
+
+ if ($schedule == "") {
+ return false;
+ }
+ /* loop through firewall rules looking for schedule in use */
+ if (is_array($config['filter']['rule'])) {
+ foreach ($config['filter']['rule'] as $rule) {
+ if ($rule['sched'] == $schedule) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/****f* pfsense-utils/setup_polling
+ * NAME
+ * sets up polling
+ * INPUTS
+ *
+ * RESULT
+ * null
+ * NOTES
+ *
+ ******/
+function setup_polling() {
+ global $g, $config;
+
+ if (isset($config['system']['polling'])) {
+ set_single_sysctl("kern.polling.idle_poll", "1");
+ } else {
+ set_single_sysctl("kern.polling.idle_poll", "0");
+ }
+
+ if ($config['system']['polling_each_burst']) {
+ set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
+ }
+ if ($config['system']['polling_burst_max']) {
+ set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
+ }
+ if ($config['system']['polling_user_frac']) {
+ set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
+ }
+}
+
+/****f* pfsense-utils/setup_microcode
+ * NAME
+ * enumerates all interfaces and calls enable_hardware_offloading which
+ * enables a NIC's supported hardware features.
+ * INPUTS
+ *
+ * RESULT
+ * null
+ * NOTES
+ * This function only supports the fxp driver's loadable microcode.
+ ******/
+function setup_microcode() {
+
+ /* if list */
+ $iflist = get_configured_interface_list(false, true);
+ foreach ($iflist as $if => $ifdescr) {
+ enable_hardware_offloading($if);
+ }
+ unset($iflist);
+}
+
+/****f* pfsense-utils/get_carp_status
+ * NAME
+ * get_carp_status - Return whether CARP is enabled or disabled.
+ * RESULT
+ * boolean - true if CARP is enabled, false if otherwise.
+ ******/
+function get_carp_status() {
+ /* grab the current status of carp */
+ $status = get_single_sysctl('net.inet.carp.allow');
+ return (intval($status) > 0);
+}
+
+/*
+ * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
+
+ */
+function convert_ip_to_network_format($ip, $subnet) {
+ $ipsplit = explode('.', $ip);
+ $string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
+ return $string;
+}
+
+/*
+ * get_carp_interface_status($carpinterface): returns the status of a carp ip
+ */
+function get_carp_interface_status($carpinterface) {
+
+ $interface = get_real_interface($interface);
+ $carp_query = '';
+ $_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep -v grep | /usr/bin/grep carp: | /usr/bin/head -n 1", $carp_query);
+ foreach ($carp_query as $int) {
+ if (stripos($int, "MASTER")) {
+ return "MASTER";
+ }
+ if (stripos($int, "BACKUP")) {
+ return "BACKUP";
+ }
+ if (stripos($int, "INIT")) {
+ return "INIT";
+ }
+ }
+ return;
+}
+
+/*
+ * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
+ */
+function get_pfsync_interface_status($pfsyncinterface) {
+ if (!does_interface_exist($pfsyncinterface)) {
+ return;
+ }
+
+ return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
+}
+
+/*
+ * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
+ */
+function add_rule_to_anchor($anchor, $rule, $label) {
+ mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
+}
+
+/*
+ * remove_text_from_file
+ * remove $text from file $file
+ */
+function remove_text_from_file($file, $text) {
+ if (!file_exists($file) && !is_writable($file)) {
+ return;
+ }
+ $filecontents = file_get_contents($file);
+ $text = str_replace($text, "", $filecontents);
+ @file_put_contents($file, $text);
+}
+
+/*
+ * after_sync_bump_adv_skew(): create skew values by 1S
+ */
+function after_sync_bump_adv_skew() {
+ global $config, $g;
+ $processed_skew = 1;
+ $a_vip = &$config['virtualip']['vip'];
+ foreach ($a_vip as $vipent) {
+ if ($vipent['advskew'] <> "") {
+ $processed_skew = 1;
+ $vipent['advskew'] = $vipent['advskew']+1;
+ }
+ }
+ if ($processed_skew == 1) {
+ write_config(gettext("After synch increase advertising skew"));
+ }
+}
+
+/*
+ * get_filename_from_url($url): converts a url to its filename.
+ */
+function get_filename_from_url($url) {
+ return basename($url);
+}
+
+/*
+ * get_dir: return an array of $dir
+ */
+function get_dir($dir) {
+ $dir_array = array();
+ $d = dir($dir);
+ while (false !== ($entry = $d->read())) {
+ array_push($dir_array, $entry);
+ }
+ $d->close();
+ return $dir_array;
+}
+
+/****f* pfsense-utils/WakeOnLan
+ * NAME
+ * WakeOnLan - Wake a machine up using the wake on lan format/protocol
+ * RESULT
+ * true/false - true if the operation was successful
+ ******/
+function WakeOnLan($addr, $mac) {
+ $addr_byte = explode(':', $mac);
+ $hw_addr = '';
+
+ for ($a = 0; $a < 6; $a++) {
+ $hw_addr .= chr(hexdec($addr_byte[$a]));
+ }
+
+ $msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
+
+ for ($a = 1; $a <= 16; $a++) {
+ $msg .= $hw_addr;
+ }
+
+ // send it to the broadcast address using UDP
+ $s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ if ($s == false) {
+ log_error(gettext("Error creating socket!"));
+ log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
+ } else {
+ // setting a broadcast option to socket:
+ $opt_ret = socket_set_option($s, 1, 6, TRUE);
+ if ($opt_ret < 0) {
+ log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
+ }
+ $e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
+ socket_close($s);
+ log_error(sprintf(gettext('Magic Packet sent (%1$s) to {%2$s} MAC=%3$s'), $e, $addr, $mac));
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * reverse_strrchr($haystack, $needle): Return everything in $haystack up to the *last* instance of $needle.
+ * Useful for finding paths and stripping file extensions.
+ */
+function reverse_strrchr($haystack, $needle) {
+ if (!is_string($haystack)) {
+ return;
+ }
+ return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
+}
+
+/*
+ * backup_config_section($section): returns as an xml file string of
+ * the configuration section
+ */
+function backup_config_section($section_name) {
+ global $config;
+ $new_section = &$config[$section_name];
+ /* generate configuration XML */
+ $xmlconfig = dump_xml_config($new_section, $section_name);
+ $xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
+ return $xmlconfig;
+}
+
+/*
+ * restore_config_section($section_name, new_contents): restore a configuration section,
+ * and write the configuration out
+ * to disk/cf.
+ */
+function restore_config_section($section_name, $new_contents) {
+ global $config, $g;
+ conf_mount_rw();
+ $fout = fopen("{$g['tmp_path']}/tmpxml", "w");
+ fwrite($fout, $new_contents);
+ fclose($fout);
+
+ $xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
+ if ($xml['pfsense']) {
+ $xml = $xml['pfsense'];
+ }
+ else if ($xml['m0n0wall']) {
+ $xml = $xml['m0n0wall'];
+ }
+ if ($xml[$section_name]) {
+ $section_xml = $xml[$section_name];
+ } else {
+ $section_xml = -1;
+ }
+
+ @unlink($g['tmp_path'] . "/tmpxml");
+ if ($section_xml === -1) {
+ return false;
+ }
+ $config[$section_name] = &$section_xml;
+ if (file_exists("{$g['tmp_path']}/config.cache")) {
+ unlink("{$g['tmp_path']}/config.cache");
+ }
+ write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
+ disable_security_checks();
+ conf_mount_ro();
+ return true;
+}
+
+/*
+ * merge_config_section($section_name, new_contents): restore a configuration section,
+ * and write the configuration out
+ * to disk/cf. But preserve the prior
+ * structure if needed
+ */
+function merge_config_section($section_name, $new_contents) {
+ global $config;
+ conf_mount_rw();
+ $fname = get_tmp_filename();
+ $fout = fopen($fname, "w");
+ fwrite($fout, $new_contents);
+ fclose($fout);
+ $section_xml = parse_xml_config($fname, $section_name);
+ $config[$section_name] = $section_xml;
+ unlink($fname);
+ write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
+ disable_security_checks();
+ conf_mount_ro();
+ return;
+}
+
+/*
+ * http_post($server, $port, $url, $vars): does an http post to a web server
+ * posting the vars array.
+ * written by nf@bigpond.net.au
+ */
+function http_post($server, $port, $url, $vars) {
+ $user_agent = "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)";
+ $urlencoded = "";
+ while (list($key, $value) = each($vars)) {
+ $urlencoded .= urlencode($key) . "=" . urlencode($value) . "&";
+ }
+ $urlencoded = substr($urlencoded, 0, -1);
+ $content_length = strlen($urlencoded);
+ $headers = "POST $url HTTP/1.1
+Accept: */*
+Accept-Language: en-au
+Content-Type: application/x-www-form-urlencoded
+User-Agent: $user_agent
+Host: $server
+Connection: Keep-Alive
+Cache-Control: no-cache
+Content-Length: $content_length
+
+";
+
+ $errno = "";
+ $errstr = "";
+ $fp = fsockopen($server, $port, $errno, $errstr);
+ if (!$fp) {
+ return false;
+ }
+
+ fputs($fp, $headers);
+ fputs($fp, $urlencoded);
+
+ $ret = "";
+ while (!feof($fp)) {
+ $ret .= fgets($fp, 1024);
+ }
+ fclose($fp);
+
+ return $ret;
+}
+
+/*
+ * php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
+ */
+if (!function_exists('php_check_syntax')) {
+ global $g;
+ function php_check_syntax($code_to_check, &$errormessage) {
+ return false;
+ $fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
+ $code = $_POST['content'];
+ $code = str_replace("<?php", "", $code);
+ $code = str_replace("?>", "", $code);
+ fwrite($fout, "<?php\n\n");
+ fwrite($fout, $code_to_check);
+ fwrite($fout, "\n\n?>\n");
+ fclose($fout);
+ $command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
+ $output = exec_command($command);
+ if (stristr($output, "Errors parsing") == false) {
+ echo "false\n";
+ $errormessage = '';
+ return(false);
+ } else {
+ $errormessage = $output;
+ return(true);
+ }
+ }
+}
+
+/*
+ * php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
+ */
+if (!function_exists('php_check_syntax')) {
+ function php_check_syntax($code_to_check, &$errormessage) {
+ return false;
+ $command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
+ $output = exec_command($command);
+ if (stristr($output, "Errors parsing") == false) {
+ echo "false\n";
+ $errormessage = '';
+ return(false);
+ } else {
+ $errormessage = $output;
+ return(true);
+ }
+ }
+}
+
+/*
+ * rmdir_recursive($path, $follow_links=false)
+ * Recursively remove a directory tree (rm -rf path)
+ * This is for directories _only_
+ */
+function rmdir_recursive($path, $follow_links=false) {
+ $to_do = glob($path);
+ if (!is_array($to_do)) {
+ $to_do = array($to_do);
+ }
+ foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
+ if (file_exists($workingdir)) {
+ if (is_dir($workingdir)) {
+ $dir = opendir($workingdir);
+ while ($entry = readdir($dir)) {
+ if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
+ unlink("$workingdir/$entry");
+ } elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
+ rmdir_recursive("$workingdir/$entry");
+ }
+ }
+ closedir($dir);
+ rmdir($workingdir);
+ } elseif (is_file($workingdir)) {
+ unlink($workingdir);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * call_pfsense_method(): Call a method exposed by the pfsense.org XMLRPC server.
+ */
+function call_pfsense_method($method, $params, $timeout = 0) {
+ global $g, $config;
+
+ $xmlrpc_base_url = get_active_xml_rpc_base_url();
+ $xmlrpc_path = $g['xmlrpcpath'];
+
+ $xmlrpcfqdn = preg_replace("(https?://)", "", $xmlrpc_base_url);
+ $ip = gethostbyname($xmlrpcfqdn);
+ if ($ip == $xmlrpcfqdn) {
+ return false;
+ }
+
+ $msg = new XML_RPC_Message($method, array(XML_RPC_Encode($params)));
+ $port = 0;
+ $proxyurl = "";
+ $proxyport = 0;
+ $proxyuser = "";
+ $proxypass = "";
+ if (!empty($config['system']['proxyurl'])) {
+ $proxyurl = $config['system']['proxyurl'];
+ }
+ if (!empty($config['system']['proxyport']) && is_numeric($config['system']['proxyport'])) {
+ $proxyport = $config['system']['proxyport'];
+ }
+ if (!empty($config['system']['proxyuser'])) {
+ $proxyuser = $config['system']['proxyuser'];
+ }
+ if (!empty($config['system']['proxypass'])) {
+ $proxypass = $config['system']['proxypass'];
+ }
+ $cli = new XML_RPC_Client($xmlrpc_path, $xmlrpc_base_url, $port, $proxyurl, $proxyport, $proxyuser, $proxypass);
+ // If the ALT PKG Repo has a username/password set, use it.
+ if ($config['system']['altpkgrepo']['username'] &&
+ $config['system']['altpkgrepo']['password']) {
+ $username = $config['system']['altpkgrepo']['username'];
+ $password = $config['system']['altpkgrepo']['password'];
+ $cli->setCredentials($username, $password);
+ }
+ $resp = $cli->send($msg, $timeout);
+ if (!is_object($resp)) {
+ log_error(sprintf(gettext("XMLRPC communication error: %s"), $cli->errstr));
+ return false;
+ } elseif ($resp->faultCode()) {
+ log_error(sprintf(gettext('XMLRPC request failed with error %1$s: %2$s'), $resp->faultCode(), $resp->faultString()));
+ return false;
+ } else {
+ return XML_RPC_Decode($resp->value());
+ }
+}
+
+/*
+ * check_firmware_version(): Check whether the current firmware installed is the most recently released.
+ */
+function check_firmware_version($tocheck = "all", $return_php = true) {
+ global $g, $config;
+
+ $xmlrpc_base_url = get_active_xml_rpc_base_url();
+ $xmlrpcfqdn = preg_replace("(https?://)", "", $xmlrpc_base_url);
+ $ip = gethostbyname($xmlrpcfqdn);
+ if ($ip == $xmlrpcfqdn) {
+ return false;
+ }
+ $version = php_uname('r');
+ $version = explode('-', $version);
+ $rawparams = array("firmware" => array("version" => $g['product_version']),
+ "kernel" => array("version" => $version[0]),
+ "base" => array("version" => $version[0]),
+ "platform" => trim(file_get_contents('/etc/platform')),
+ "config_version" => $config['version']
+ );
+ unset($version);
+
+ if ($tocheck == "all") {
+ $params = $rawparams;
+ } else {
+ foreach ($tocheck as $check) {
+ $params['check'] = $rawparams['check'];
+ $params['platform'] = $rawparams['platform'];
+ }
+ }
+ if ($config['system']['firmware']['branch']) {
+ $params['branch'] = $config['system']['firmware']['branch'];
+ }
+
+ /* XXX: What is this method? */
+ if (!($versions = call_pfsense_method('pfsense.get_firmware_version', $params))) {
+ return false;
+ } else {
+ $versions["current"] = $params;
+ }
+
+ return $versions;
+}
+
+/*
+ * host_firmware_version(): Return the versions used in this install
+ */
+function host_firmware_version($tocheck = "") {
+ global $g, $config;
+
+ $os_version = trim(substr(php_uname("r"), 0, strpos(php_uname("r"), '-')));
+
+ return array(
+ "firmware" => array("version" => $g['product_version']),
+ "kernel" => array("version" => $os_version),
+ "base" => array("version" => $os_version),
+ "platform" => trim(file_get_contents('/etc/platform', " \n")),
+ "config_version" => $config['version']
+ );
+}
+
+function get_disk_info() {
+ $diskout = "";
+ exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
+ return explode(' ', $diskout[0]);
+}
+
+/****f* pfsense-utils/strncpy
+ * NAME
+ * strncpy - copy strings
+ * INPUTS
+ * &$dst, $src, $length
+ * RESULT
+ * none
+ ******/
+function strncpy(&$dst, $src, $length) {
+ if (strlen($src) > $length) {
+ $dst = substr($src, 0, $length);
+ } else {
+ $dst = $src;
+ }
+}
+
+/****f* pfsense-utils/reload_interfaces_sync
+ * NAME
+ * reload_interfaces - reload all interfaces
+ * INPUTS
+ * none
+ * RESULT
+ * none
+ ******/
+function reload_interfaces_sync() {
+ global $config, $g;
+
+ if ($g['debug']) {
+ log_error(gettext("reload_interfaces_sync() is starting."));
+ }
+
+ /* parse config.xml again */
+ $config = parse_config(true);
+
+ /* enable routing */
+ system_routing_enable();
+ if ($g['debug']) {
+ log_error(gettext("Enabling system routing"));
+ }
+
+ if ($g['debug']) {
+ log_error(gettext("Cleaning up Interfaces"));
+ }
+
+ /* set up interfaces */
+ interfaces_configure();
+}
+
+/****f* pfsense-utils/reload_all
+ * NAME
+ * reload_all - triggers a reload of all settings
+ * * INPUTS
+ * none
+ * RESULT
+ * none
+ ******/
+function reload_all() {
+ send_event("service reload all");
+}
+
+/****f* pfsense-utils/reload_interfaces
+ * NAME
+ * reload_interfaces - triggers a reload of all interfaces
+ * INPUTS
+ * none
+ * RESULT
+ * none
+ ******/
+function reload_interfaces() {
+ send_event("interface all reload");
+}
+
+/****f* pfsense-utils/reload_all_sync
+ * NAME
+ * reload_all - reload all settings
+ * * INPUTS
+ * none
+ * RESULT
+ * none
+ ******/
+function reload_all_sync() {
+ global $config, $g;
+
+ /* parse config.xml again */
+ $config = parse_config(true);
+
+ /* set up our timezone */
+ system_timezone_configure();
+
+ /* set up our hostname */
+ system_hostname_configure();
+
+ /* make hosts file */
+ system_hosts_generate();
+
+ /* generate resolv.conf */
+ system_resolvconf_generate();
+
+ /* enable routing */
+ system_routing_enable();
+
+ /* set up interfaces */
+ interfaces_configure();
+
+ /* start dyndns service */
+ services_dyndns_configure();
+
+ /* configure cron service */
+ configure_cron();
+
+ /* start the NTP client */
+ system_ntp_configure();
+
+ /* sync pw database */
+ conf_mount_rw();
+ unlink_if_exists("/etc/spwd.db.tmp");
+ mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
+ conf_mount_ro();
+
+ /* restart sshd */
+ send_event("service restart sshd");
+
+ /* restart webConfigurator if needed */
+ send_event("service restart webgui");
+}
+
+function setup_serial_port($when = "save", $path = "") {
+ global $g, $config;
+ conf_mount_rw();
+ $ttys_file = "{$path}/etc/ttys";
+ $boot_config_file = "{$path}/boot.config";
+ $loader_conf_file = "{$path}/boot/loader.conf";
+ /* serial console - write out /boot.config */
+ if (file_exists($boot_config_file)) {
+ $boot_config = file_get_contents($boot_config_file);
+ } else {
+ $boot_config = "";
+ }
+
+ $serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
+ if ($g['platform'] != "cdrom") {
+ $serial_only = false;
+
+ if (($g['platform'] == "nanobsd") && !file_exists("/etc/nano_use_vga.txt")) {
+ $serial_only = true;
+ } else {
+ $specific_platform = system_identify_specific_platform();
+ if ($specific_platform['name'] == 'RCC-VE' ||
+ $specific_platform['name'] == 'RCC-DFF') {
+ $serial_only = true;
+ }
+ }
+
+ $boot_config_split = explode("\n", $boot_config);
+ $fd = fopen($boot_config_file, "w");
+ if ($fd) {
+ foreach ($boot_config_split as $bcs) {
+ if (stristr($bcs, "-D") || stristr($bcs, "-h")) {
+ /* DONT WRITE OUT, WE'LL DO IT LATER */
+ } else {
+ if ($bcs <> "") {
+ fwrite($fd, "{$bcs}\n");
+ }
+ }
+ }
+ if ($serial_only === true) {
+ fwrite($fd, "-S{$serialspeed} -h");
+ } else if (is_serial_enabled()) {
+ fwrite($fd, "-S{$serialspeed} -D");
+ }
+ fclose($fd);
+ }
+
+ /* serial console - write out /boot/loader.conf */
+ if ($when == "upgrade") {
+ system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
+ }
+ $boot_config = file_get_contents($loader_conf_file);
+ $boot_config_split = explode("\n", $boot_config);
+ if (count($boot_config_split) > 0) {
+ $new_boot_config = array();
+ // Loop through and only add lines that are not empty, and which
+ // do not contain a console directive.
+ foreach ($boot_config_split as $bcs) {
+ if (!empty($bcs) &&
+ (stripos($bcs, "console") === false) &&
+ (stripos($bcs, "boot_multicons") === false) &&
+ (stripos($bcs, "boot_serial") === false) &&
+ (stripos($bcs, "hw.usb.no_pf") === false) &&
+ (stripos($bcs, "hint.uart.0.flags") === false) &&
+ (stripos($bcs, "hint.uart.1.flags") === false)) {
+ $new_boot_config[] = $bcs;
+ }
+ }
+
+ if ($serial_only === true) {
+ $new_boot_config[] = 'boot_serial="YES"';
+ $new_boot_config[] = 'console="comconsole"';
+ } else if (is_serial_enabled()) {
+ $new_boot_config[] = 'boot_multicons="YES"';
+ $new_boot_config[] = 'boot_serial="YES"';
+ $primaryconsole = isset($g['primaryconsole_force']) ? $g['primaryconsole_force'] : $config['system']['primaryconsole'];
+ switch ($primaryconsole) {
+ case "video":
+ $new_boot_config[] = 'console="vidconsole,comconsole"';
+ break;
+ case "serial":
+ default:
+ $new_boot_config[] = 'console="comconsole,vidconsole"';
+ }
+ }
+ $new_boot_config[] = 'comconsole_speed="' . $serialspeed . '"';
+
+ $specplatform = system_identify_specific_platform();
+ if ($specplatform['name'] == 'RCC-VE' ||
+ $specplatform['name'] == 'RCC-DFF') {
+ $new_boot_config[] = 'comconsole_port="0x2F8"';
+ $new_boot_config[] = 'hint.uart.0.flags="0x00"';
+ $new_boot_config[] = 'hint.uart.1.flags="0x10"';
+ }
+ $new_boot_config[] = 'hw.usb.no_pf="1"';
+
+ file_put_contents($loader_conf_file, implode("\n", $new_boot_config) . "\n");
+ }
+ }
+ $ttys = file_get_contents($ttys_file);
+ $ttys_split = explode("\n", $ttys);
+ $fd = fopen($ttys_file, "w");
+
+ $on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
+
+ if (isset($config['system']['disableconsolemenu'])) {
+ $console_type = 'Pc';
+ $serial_type = 'std.' . $serialspeed;
+ } else {
+ $console_type = 'al.Pc';
+ $serial_type = 'al.' . $serialspeed;
+ }
+ foreach ($ttys_split as $tty) {
+ if (stristr($tty, "ttyv0")) {
+ fwrite($fd, "ttyv0 \"/usr/libexec/getty {$console_type}\" cons25 on secure\n");
+ } else if (stristr($tty, "ttyu")) {
+ $ttyn = substr($tty, 0, 5);
+ fwrite($fd, "{$ttyn} \"/usr/libexec/getty {$serial_type}\" cons25 {$on_off} secure\n");
+ } else {
+ fwrite($fd, $tty . "\n");
+ }
+ }
+ unset($on_off, $console_type, $serial_type);
+ fclose($fd);
+ if ($when != "upgrade") {
+ reload_ttys();
+ }
+
+ conf_mount_ro();
+ return;
+}
+
+function is_serial_enabled() {
+ global $g, $config;
+
+ if (!isset($g['enableserial_force']) &&
+ !isset($config['system']['enableserial']) &&
+ ($g['platform'] == "pfSense" || $g['platform'] == "cdrom" || file_exists("/etc/nano_use_vga.txt"))) {
+ return false;
+ }
+
+ return true;
+}
+
+function reload_ttys() {
+ // Send a HUP signal to init will make it reload /etc/ttys
+ posix_kill(1, SIGHUP);
+}
+
+function print_value_list($list, $count = 10, $separator = ",") {
+ $list = implode($separator, array_slice($list, 0, $count));
+ if (count($list) < $count) {
+ $list .= ".";
+ } else {
+ $list .= "...";
+ }
+ return $list;
+}
+
+/* DHCP enabled on any interfaces? */
+function is_dhcp_server_enabled() {
+ global $config;
+
+ if (!is_array($config['dhcpd'])) {
+ return false;
+ }
+
+ foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
+ if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* DHCP enabled on any interfaces? */
+function is_dhcpv6_server_enabled() {
+ global $config;
+
+ if (is_array($config['interfaces'])) {
+ foreach ($config['interfaces'] as $ifcfg) {
+ if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
+ return true;
+ }
+ }
+ }
+
+ if (!is_array($config['dhcpdv6'])) {
+ return false;
+ }
+
+ foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
+ if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* radvd enabled on any interfaces? */
+function is_radvd_enabled() {
+ global $config;
+
+ if (!is_array($config['dhcpdv6'])) {
+ $config['dhcpdv6'] = array();
+ }
+
+ $dhcpdv6cfg = $config['dhcpdv6'];
+ $Iflist = get_configured_interface_list();
+
+ /* handle manually configured DHCP6 server settings first */
+ foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
+ if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
+ continue;
+ }
+
+ if (!isset($dhcpv6ifconf['ramode'])) {
+ $dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
+ }
+
+ if ($dhcpv6ifconf['ramode'] == "disabled") {
+ continue;
+ }
+
+ $ifcfgipv6 = get_interface_ipv6($dhcpv6if);
+ if (!is_ipaddrv6($ifcfgipv6)) {
+ continue;
+ }
+
+ return true;
+ }
+
+ /* handle DHCP-PD prefixes and 6RD dynamic interfaces */
+ foreach ($Iflist as $if => $ifdescr) {
+ if (!isset($config['interfaces'][$if]['track6-interface'])) {
+ continue;
+ }
+ if (!isset($config['interfaces'][$if]['enable'])) {
+ continue;
+ }
+
+ $ifcfgipv6 = get_interface_ipv6($if);
+ if (!is_ipaddrv6($ifcfgipv6)) {
+ continue;
+ }
+
+ $ifcfgsnv6 = get_interface_subnetv6($if);
+ $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
+
+ if (!is_ipaddrv6($subnetv6)) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/* Any PPPoE servers enabled? */
+function is_pppoe_server_enabled() {
+ global $config;
+
+ $pppoeenable = false;
+
+ if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
+ return false;
+ }
+
+ foreach ($config['pppoes']['pppoe'] as $pppoes) {
+ if ($pppoes['mode'] == 'server') {
+ $pppoeenable = true;
+ }
+ }
+
+ return $pppoeenable;
+}
+
+function convert_seconds_to_hms($sec) {
+ $min = $hrs = 0;
+ if ($sec != 0) {
+ $min = floor($sec/60);
+ $sec %= 60;
+ }
+ if ($min != 0) {
+ $hrs = floor($min/60);
+ $min %= 60;
+ }
+ if ($sec < 10) {
+ $sec = "0".$sec;
+ }
+ if ($min < 10) {
+ $min = "0".$min;
+ }
+ if ($hrs < 10) {
+ $hrs = "0".$hrs;
+ }
+ $result = $hrs.":".$min.":".$sec;
+ return $result;
+}
+
+/* Compute the total uptime from the ppp uptime log file in the conf directory */
+
+function get_ppp_uptime($port) {
+ if (file_exists("/conf/{$port}.log")) {
+ $saved_time = file_get_contents("/conf/{$port}.log");
+ $uptime_data = explode("\n", $saved_time);
+ $sec = 0;
+ foreach ($uptime_data as $upt) {
+ $sec += substr($upt, 1 + strpos($upt, " "));
+ }
+ return convert_seconds_to_hms($sec);
+ } else {
+ $total_time = gettext("No history data found!");
+ return $total_time;
+ }
+}
+
+//returns interface information
+function get_interface_info($ifdescr) {
+ global $config, $g;
+
+ $ifinfo = array();
+ if (empty($config['interfaces'][$ifdescr])) {
+ return;
+ }
+ $ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
+ $ifinfo['if'] = get_real_interface($ifdescr);
+
+ $chkif = $ifinfo['if'];
+ $ifinfotmp = pfSense_get_interface_addresses($chkif);
+ $ifinfo['status'] = $ifinfotmp['status'];
+ if (empty($ifinfo['status'])) {
+ $ifinfo['status'] = "down";
+ }
+ $ifinfo['macaddr'] = $ifinfotmp['macaddr'];
+ $ifinfo['mtu'] = $ifinfotmp['mtu'];
+ $ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
+ $ifinfo['subnet'] = $ifinfotmp['subnet'];
+ $ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
+ $ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
+ $ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
+ if (isset($ifinfotmp['link0'])) {
+ $link0 = "down";
+ }
+ $ifinfotmp = pfSense_get_interface_stats($chkif);
+ // $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
+ // $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
+ $ifinfo['inerrs'] = $ifinfotmp['inerrs'];
+ $ifinfo['outerrs'] = $ifinfotmp['outerrs'];
+ $ifinfo['collisions'] = $ifinfotmp['collisions'];
+
+ /* Use pfctl for non wrapping 64 bit counters */
+ /* Pass */
+ exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
+ $pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
+ $pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
+ $pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
+ $pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
+ $in4_pass = $pf_in4_pass[5];
+ $out4_pass = $pf_out4_pass[5];
+ $in4_pass_packets = $pf_in4_pass[3];
+ $out4_pass_packets = $pf_out4_pass[3];
+ $in6_pass = $pf_in6_pass[5];
+ $out6_pass = $pf_out6_pass[5];
+ $in6_pass_packets = $pf_in6_pass[3];
+ $out6_pass_packets = $pf_out6_pass[3];
+ $ifinfo['inbytespass'] = $in4_pass + $in6_pass;
+ $ifinfo['outbytespass'] = $out4_pass + $out6_pass;
+ $ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
+ $ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
+
+ /* Block */
+ $pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
+ $pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
+ $pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
+ $pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
+ $in4_block = $pf_in4_block[5];
+ $out4_block = $pf_out4_block[5];
+ $in4_block_packets = $pf_in4_block[3];
+ $out4_block_packets = $pf_out4_block[3];
+ $in6_block = $pf_in6_block[5];
+ $out6_block = $pf_out6_block[5];
+ $in6_block_packets = $pf_in6_block[3];
+ $out6_block_packets = $pf_out6_block[3];
+ $ifinfo['inbytesblock'] = $in4_block + $in6_block;
+ $ifinfo['outbytesblock'] = $out4_block + $out6_block;
+ $ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
+ $ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
+
+ $ifinfo['inbytes'] = $in4_pass + $in6_pass;
+ $ifinfo['outbytes'] = $out4_pass + $out6_pass;
+ $ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
+ $ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
+
+ $ifconfiginfo = "";
+ $link_type = $config['interfaces'][$ifdescr]['ipaddr'];
+ switch ($link_type) {
+ /* DHCP? -> see if dhclient is up */
+ case "dhcp":
+ /* see if dhclient is up */
+ if (find_dhclient_process($ifinfo['if']) != 0) {
+ $ifinfo['dhcplink'] = "up";
+ } else {
+ $ifinfo['dhcplink'] = "down";
+ }
+
+ break;
+ /* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
+ case "pppoe":
+ case "pptp":
+ case "l2tp":
+ if ($ifinfo['status'] == "up" && !isset($link0)) {
+ /* get PPPoE link status for dial on demand */
+ $ifinfo["{$link_type}link"] = "up";
+ } else {
+ $ifinfo["{$link_type}link"] = "down";
+ }
+
+ break;
+ /* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
+ case "ppp":
+ if ($ifinfo['status'] == "up") {
+ $ifinfo['ppplink'] = "up";
+ } else {
+ $ifinfo['ppplink'] = "down" ;
+ }
+
+ if (empty($ifinfo['status'])) {
+ $ifinfo['status'] = "down";
+ }
+
+ if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
+ if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
+ break;
+ }
+ }
+ }
+ $dev = $ppp['ports'];
+ if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
+ break;
+ }
+ if (!file_exists($dev)) {
+ $ifinfo['nodevice'] = 1;
+ $ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
+ }
+
+ $usbmodemoutput = array();
+ exec("usbconfig", $usbmodemoutput);
+ $mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
+ if (file_exists($mondev)) {
+ $cellstats = file($mondev);
+ /* skip header */
+ $a_cellstats = explode(",", $cellstats[1]);
+ if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
+ $ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
+ $ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
+ $ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
+ $ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
+ }
+ if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
+ $ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
+ $ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
+ $ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
+ $ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
+ }
+ $ifinfo['cell_upstream'] = $a_cellstats[4];
+ $ifinfo['cell_downstream'] = trim($a_cellstats[5]);
+ $ifinfo['cell_sent'] = $a_cellstats[6];
+ $ifinfo['cell_received'] = trim($a_cellstats[7]);
+ $ifinfo['cell_bwupstream'] = $a_cellstats[8];
+ $ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
+ }
+ // Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
+ if (isset($ppp['uptime'])) {
+ $ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
+ $sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
+ $ifinfo['ppp_uptime'] = convert_seconds_to_hms($sec);
+ }
+
+ if ($ifinfo['status'] == "up") {
+ /* try to determine media with ifconfig */
+ unset($ifconfiginfo);
+ exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
+ $wifconfiginfo = array();
+ if (is_interface_wireless($ifdescr)) {
+ exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
+ array_shift($wifconfiginfo);
+ }
+ $matches = "";
+ foreach ($ifconfiginfo as $ici) {
+
+ /* don't list media/speed for wireless cards, as it always
+ displays 2 Mbps even though clients can connect at 11 Mbps */
+ if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
+ $ifinfo['media'] = $matches[1];
+ } else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
+ $ifinfo['media'] = $matches[1];
+ } else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
+ $ifinfo['media'] = $matches[1];
+ }
+
+ if (preg_match("/status: (.*)$/", $ici, $matches)) {
+ if ($matches[1] != "active") {
+ $ifinfo['status'] = $matches[1];
+ }
+ if ($ifinfo['status'] == gettext("running")) {
+ $ifinfo['status'] = gettext("up");
+ }
+ }
+ if (preg_match("/channel (\S*)/", $ici, $matches)) {
+ $ifinfo['channel'] = $matches[1];
+ }
+ if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
+ if ($matches[1][0] == '"') {
+ $ifinfo['ssid'] = substr($matches[1], 1, -1);
+ }
+ else {
+ $ifinfo['ssid'] = $matches[1];
+ }
+ }
+ if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
+ $ifinfo['laggproto'] = $matches[1];
+ }
+ if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
+ $ifinfo['laggport'][] = $matches[1];
+ }
+ }
+ foreach ($wifconfiginfo as $ici) {
+ $elements = preg_split("/[ ]+/i", $ici);
+ if ($elements[0] != "") {
+ $ifinfo['bssid'] = $elements[0];
+ }
+ if ($elements[3] != "") {
+ $ifinfo['rate'] = $elements[3];
+ }
+ if ($elements[4] != "") {
+ $ifinfo['rssi'] = $elements[4];
+ }
+ }
+ /* lookup the gateway */
+ if (interface_has_gateway($ifdescr)) {
+ $ifinfo['gateway'] = get_interface_gateway($ifdescr);
+ $ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
+ }
+ }
+
+ $bridge = "";
+ $bridge = link_interface_to_bridge($ifdescr);
+ if ($bridge) {
+ $bridge_text = `/sbin/ifconfig {$bridge}`;
+ if (stristr($bridge_text, "blocking") <> false) {
+ $ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
+ $ifinfo['bridgeint'] = $bridge;
+ } else if (stristr($bridge_text, "learning") <> false) {
+ $ifinfo['bridge'] = gettext("learning");
+ $ifinfo['bridgeint'] = $bridge;
+ } else if (stristr($bridge_text, "forwarding") <> false) {
+ $ifinfo['bridge'] = gettext("forwarding");
+ $ifinfo['bridgeint'] = $bridge;
+ }
+ }
+
+ return $ifinfo;
+}
+
+//returns cpu speed of processor. Good for determining capabilities of machine
+function get_cpu_speed() {
+ return get_single_sysctl("hw.clockrate");
+}
+
+function get_uptime_sec() {
+ $boottime = "";
+ $matches = "";
+ $boottime = get_single_sysctl("kern.boottime");
+ preg_match("/sec = (\d+)/", $boottime, $matches);
+ $boottime = $matches[1];
+ if (intval($boottime) == 0) {
+ return 0;
+ }
+
+ $uptime = time() - $boottime;
+ return $uptime;
+}
+
+function add_hostname_to_watch($hostname) {
+ if (!is_dir("/var/db/dnscache")) {
+ mkdir("/var/db/dnscache");
+ }
+ $result = array();
+ if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
+ $domrecords = array();
+ $domips = array();
+ exec("host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
+ if ($rethost == 0) {
+ foreach ($domrecords as $domr) {
+ $doml = explode(" ", $domr);
+ $domip = $doml[3];
+ /* fill array with domain ip addresses */
+ if (is_ipaddr($domip)) {
+ $domips[] = $domip;
+ }
+ }
+ }
+ sort($domips);
+ $contents = "";
+ if (!empty($domips)) {
+ foreach ($domips as $ip) {
+ $contents .= "$ip\n";
+ }
+ }
+ file_put_contents("/var/db/dnscache/$hostname", $contents);
+ /* Remove empty elements */
+ $result = array_filter(explode("\n", $contents), 'strlen');
+ }
+ return $result;
+}
+
+function is_fqdn($fqdn) {
+ $hostname = false;
+ if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
+ $hostname = true;
+ }
+ if (preg_match("/\.\./", $fqdn)) {
+ $hostname = false;
+ }
+ if (preg_match("/^\./i", $fqdn)) {
+ $hostname = false;
+ }
+ if (preg_match("/\//i", $fqdn)) {
+ $hostname = false;
+ }
+ return($hostname);
+}
+
+function pfsense_default_state_size() {
+ /* get system memory amount */
+ $memory = get_memory();
+ $physmem = $memory[0];
+ /* Be cautious and only allocate 10% of system memory to the state table */
+ $max_states = (int) ($physmem/10)*1000;
+ return $max_states;
+}
+
+function pfsense_default_tables_size() {
+ $current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
+ return $current;
+}
+
+function pfsense_default_table_entries_size() {
+ $current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
+ return $current;
+}
+
+/* Compare the current hostname DNS to the DNS cache we made
+ * if it has changed we return the old records
+ * if no change we return false */
+function compare_hostname_to_dnscache($hostname) {
+ if (!is_dir("/var/db/dnscache")) {
+ mkdir("/var/db/dnscache");
+ }
+ $hostname = trim($hostname);
+ if (is_readable("/var/db/dnscache/{$hostname}")) {
+ $oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
+ } else {
+ $oldcontents = "";
+ }
+ if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
+ $domrecords = array();
+ $domips = array();
+ exec("host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
+ if ($rethost == 0) {
+ foreach ($domrecords as $domr) {
+ $doml = explode(" ", $domr);
+ $domip = $doml[3];
+ /* fill array with domain ip addresses */
+ if (is_ipaddr($domip)) {
+ $domips[] = $domip;
+ }
+ }
+ }
+ sort($domips);
+ $contents = "";
+ if (!empty($domips)) {
+ foreach ($domips as $ip) {
+ $contents .= "$ip\n";
+ }
+ }
+ }
+
+ if (trim($oldcontents) != trim($contents)) {
+ if ($g['debug']) {
+ log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
+ }
+ return ($oldcontents);
+ } else {
+ return false;
+ }
+}
+
+/*
+ * load_crypto() - Load crypto modules if enabled in config.
+ */
+function load_crypto() {
+ global $config, $g;
+ $crypto_modules = array('glxsb', 'aesni');
+
+ if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
+ return false;
+ }
+
+ if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
+ log_error("Loading {$config['system']['crypto_hardware']} cryptographic accelerator module.");
+ mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
+ }
+}
+
+/*
+ * load_thermal_hardware() - Load temperature monitor kernel module
+ */
+function load_thermal_hardware() {
+ global $config, $g;
+ $thermal_hardware_modules = array('coretemp', 'amdtemp');
+
+ if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
+ return false;
+ }
+
+ if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
+ log_error("Loading {$config['system']['thermal_hardware']} thermal monitor module.");
+ mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
+ }
+}
+
+/****f* pfsense-utils/isvm
+ * NAME
+ * isvm
+ * INPUTS
+ * none
+ * RESULT
+ * returns true if machine is running under a virtual environment
+ ******/
+function isvm() {
+ $virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
+ $_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
+
+ if ($rc != 0 || !isset($output[0])) {
+ return false;
+ }
+
+ foreach ($virtualenvs as $virtualenv) {
+ if (stripos($output[0], $virtualenv) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function get_freebsd_version() {
+ $version = explode(".", php_uname("r"));
+ return $version[0];
+}
+
+function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
+ global $config, $g;
+
+ $fp = fopen($destination, "wb");
+
+ if (!$fp) {
+ return false;
+ }
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
+ curl_setopt($ch, CURLOPT_FILE, $fp);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ if (!isset($config['system']['host_uuid'])) {
+ curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
+ } else {
+ curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
+ }
+
+ if (!empty($config['system']['proxyurl'])) {
+ curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
+ if (!empty($config['system']['proxyport'])) {
+ curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
+ }
+ if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
+ @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
+ curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
+ }
+ }
+
+ @curl_exec($ch);
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ fclose($fp);
+ curl_close($ch);
+ return ($http_code == 200) ? true : $http_code;
+}
+
+function download_file_with_progress_bar($url_file, $destination_file, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
+ global $config, $g;
+ global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
+ $file_size = 1;
+ $downloaded = 1;
+ $first_progress_update = TRUE;
+ /* open destination file */
+ $fout = fopen($destination_file, "wb");
+
+ /*
+ * Originally by Author: Keyvan Minoukadeh
+ * Modified by Scott Ullrich to return Content-Length size
+ */
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url_file);
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
+ curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+ if (!isset($config['system']['host_uuid'])) {
+ curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
+ } else {
+ curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
+ }
+
+ if (!empty($config['system']['proxyurl'])) {
+ curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
+ if (!empty($config['system']['proxyport'])) {
+ curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
+ }
+ if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
+ @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
+ curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
+ }
+ }
+
+ @curl_exec($ch);
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ if ($fout) {
+ fclose($fout);
+ }
+ curl_close($ch);
+ return ($http_code == 200) ? true : $http_code;
+}
+
+function read_header($ch, $string) {
+ global $file_size, $fout;
+ $length = strlen($string);
+ $regs = "";
+ preg_match("/(Content-Length:) (.*)/", $string, $regs);
+ if ($regs[2] <> "") {
+ $file_size = intval($regs[2]);
+ }
+ ob_flush();
+ return $length;
+}
+
+function read_body($ch, $string) {
+ global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
+ global $pkg_interface;
+ $length = strlen($string);
+ $downloaded += intval($length);
+ if ($file_size > 0) {
+ $downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
+ $downloadProgress = 100 - $downloadProgress;
+ } else {
+ $downloadProgress = 0;
+ }
+ if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
+ if ($sendto == "status") {
+ if ($pkg_interface == "console") {
+ if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
+ $tostatus = $static_status . $downloadProgress . "%";
+ if ($downloadProgress == 100) {
+ $tostatus = $tostatus . "\r";
+ }
+ update_status($tostatus);
+ }
+ } else {
+ $tostatus = $static_status . $downloadProgress . "%";
+ update_status($tostatus);
+ }
+ } else {
+ if ($pkg_interface == "console") {
+ if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
+ $tooutput = $static_output . $downloadProgress . "%";
+ if ($downloadProgress == 100) {
+ $tooutput = $tooutput . "\r";
+ }
+ update_output_window($tooutput);
+ }
+ } else {
+ $tooutput = $static_output . $downloadProgress . "%";
+ update_output_window($tooutput);
+ }
+ }
+ if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
+ update_progress_bar($downloadProgress, $first_progress_update);
+ $first_progress_update = FALSE;
+ }
+ $lastseen = $downloadProgress;
+ }
+ if ($fout) {
+ fwrite($fout, $string);
+ }
+ ob_flush();
+ return $length;
+}
+
+/*
+ * update_output_window: update bottom textarea dynamically.
+ */
+function update_output_window($text) {
+ global $pkg_interface;
+ $log = preg_replace("/\n/", "\\n", $text);
+ if ($pkg_interface != "console") {
+ echo "\n<script type=\"text/javascript\">";
+ echo "\n//<![CDATA[";
+ echo "\nthis.document.forms[0].output.value = \"" . $log . "\";";
+ echo "\nthis.document.forms[0].output.scrollTop = this.document.forms[0].output.scrollHeight;";
+ echo "\n//]]>";
+ echo "\n</script>";
+ }
+ /* ensure that contents are written out */
+ ob_flush();
+}
+
+/*
+ * update_status: update top textarea dynamically.
+ */
+function update_status($status) {
+ global $pkg_interface;
+ if ($pkg_interface == "console") {
+ echo "\r{$status}";
+ } else {
+ echo "\n<script type=\"text/javascript\">";
+ echo "\n//<![CDATA[";
+ echo "\nthis.document.forms[0].status.value=\"" . $status . "\";";
+ echo "\n//]]>";
+ echo "\n</script>";
+ }
+ /* ensure that contents are written out */
+ ob_flush();
+}
+
+/*
+ * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
+ */
+function update_progress_bar($percent, $first_time) {
+ global $pkg_interface;
+ if ($percent > 100) {
+ $percent = 1;
+ }
+ if ($pkg_interface <> "console") {
+ echo "\n<script type=\"text/javascript\">";
+ echo "\n//<![CDATA[";
+ echo "\ndocument.progressbar.style.width='" . $percent . "%';";
+ echo "\n//]]>";
+ echo "\n</script>";
+ } else {
+ if (!($first_time)) {
+ echo "\x08\x08\x08\x08\x08";
+ }
+ echo sprintf("%4d%%", $percent);
+ }
+}
+
+/* Split() is being DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged. */
+if (!function_exists("split")) {
+ function split($separator, $haystack, $limit = null) {
+ log_error("deprecated split() call with separator '{$separator}'");
+ return preg_split($separator, $haystack, $limit);
+ }
+}
+
+function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
+ global $g, $config, $pconfig, $debug;
+ if (!$origname) {
+ return;
+ }
+
+ $sectionref = &$config;
+ foreach ($section as $sectionname) {
+ if (is_array($sectionref) && isset($sectionref[$sectionname])) {
+ $sectionref = &$sectionref[$sectionname];
+ } else {
+ return;
+ }
+ }
+
+ if ($debug) {
+ $fd = fopen("{$g['tmp_path']}/print_r", "a");
+ fwrite($fd, print_r($pconfig, true));
+ }
+
+ if (is_array($sectionref)) {
+ foreach ($sectionref as $itemkey => $item) {
+ if ($debug) {
+ fwrite($fd, "$itemkey\n");
+ }
+
+ $fieldfound = true;
+ $fieldref = &$sectionref[$itemkey];
+ foreach ($field as $fieldname) {
+ if (is_array($fieldref) && isset($fieldref[$fieldname])) {
+ $fieldref = &$fieldref[$fieldname];
+ } else {
+ $fieldfound = false;
+ break;
+ }
+ }
+ if ($fieldfound && $fieldref == $origname) {
+ if ($debug) {
+ fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
+ }
+ $fieldref = $new_alias_name;
+ }
+ }
+ }
+
+ if ($debug) {
+ fclose($fd);
+ }
+
+}
+
+function parse_aliases_file($filename, $type = "url", $max_items = -1) {
+ /*
+ * $filename = file to process for example blocklist like DROP: http://www.spamhaus.org/drop/drop.txt
+ * $type = if set to 'url' then subnets and ips will be returned,
+ * if set to 'url_ports' port-ranges and ports will be returned
+ * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
+ *
+ * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
+ */
+
+ $fd = @fopen($filename, 'r');
+ if (!$fd) {
+ log_error(gettext("Could not process aliases from alias: {$alias_url}"));
+ return null;
+ }
+ $items = array();
+ /* NOTE: fgetss() is not a typo RTFM before being smart */
+ while (($fc = fgetss($fd)) !== FALSE) {
+ $tmp = trim($fc, " \t\n\r");
+ if (empty($tmp)) {
+ continue;
+ }
+ $tmp_str = strstr($tmp, '#', true);
+ if (!empty($tmp_str)) {
+ $tmp = $tmp_str;
+ }
+ $tmp_str = strstr($tmp, ' ', true);
+ if (!empty($tmp_str)) {
+ $tmp = $tmp_str;
+ }
+ $valid = ($type == "url" && (is_ipaddr($tmp) || is_subnet($tmp))) ||
+ ($type == "url_ports" && (is_port($tmp) || is_portrange($tmp)));
+ if ($valid) {
+ $items[] = $tmp;
+ if (count($items) == $max_items) {
+ break;
+ }
+ }
+ }
+ fclose($fd);
+ return $items;
+}
+
+function update_alias_url_data() {
+ global $config, $g;
+
+ $updated = false;
+
+ /* item is a url type */
+ $lockkey = lock('aliasurl');
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $x => $alias) {
+ if (empty($alias['aliasurl'])) {
+ continue;
+ }
+
+ $address = null;
+ foreach ($alias['aliasurl'] as $alias_url) {
+ /* fetch down and add in */
+ $temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
+ unlink($temp_filename);
+ $verify_ssl = isset($config['system']['checkaliasesurlcert']);
+ mkdir($temp_filename);
+ download_file($alias_url, $temp_filename . "/aliases", $verify_ssl);
+
+ /* if the item is tar gzipped then extract */
+ if (stripos($alias_url, '.tgz')) {
+ if (!process_alias_tgz($temp_filename)) {
+ continue;
+ }
+ } else if (stripos($alias_url, '.zip')) {
+ if (!process_alias_unzip($temp_filename)) {
+ continue;
+ }
+ }
+ if (file_exists("{$temp_filename}/aliases")) {
+ $address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 3000);
+ mwexec("/bin/rm -rf {$temp_filename}");
+ }
+ }
+ if ($address != null) {
+ $config['aliases']['alias'][$x]['address'] = implode(" ", $address);
+ $updated = true;
+ }
+ }
+ }
+ unlock($lockkey);
+
+ /* Report status to callers as well */
+ return $updated;
+}
+
+function process_alias_unzip($temp_filename) {
+ if (!file_exists("/usr/local/bin/unzip")) {
+ log_error(gettext("Alias archive is a .zip file which cannot be decompressed because utility is missing!"));
+ return false;
+ }
+ rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.zip");
+ mwexec("/usr/local/bin/unzip {$temp_filename}/aliases.tgz -d {$temp_filename}/aliases/");
+ unlink("{$temp_filename}/aliases.zip");
+ $files_to_process = return_dir_as_array("{$temp_filename}/");
+ /* foreach through all extracted files and build up aliases file */
+ $fd = @fopen("{$temp_filename}/aliases", "w");
+ if (!$fd) {
+ log_error(gettext("Could not open {$temp_filename}/aliases for writing!"));
+ return false;
+ }
+ foreach ($files_to_process as $f2p) {
+ $tmpfd = @fopen($f2p, 'r');
+ if (!$tmpfd) {
+ log_error(gettext("The following file could not be read {$f2p} from {$temp_filename}"));
+ continue;
+ }
+ while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
+ fwrite($fd, $tmpbuf);
+ }
+ fclose($tmpfd);
+ unlink($f2p);
+ }
+ fclose($fd);
+ unset($tmpbuf);
+
+ return true;
+}
+
+function process_alias_tgz($temp_filename) {
+ if (!file_exists('/usr/bin/tar')) {
+ log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
+ return false;
+ }
+ rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
+ mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
+ unlink("{$temp_filename}/aliases.tgz");
+ $files_to_process = return_dir_as_array("{$temp_filename}/");
+ /* foreach through all extracted files and build up aliases file */
+ $fd = @fopen("{$temp_filename}/aliases", "w");
+ if (!$fd) {
+ log_error(gettext("Could not open {$temp_filename}/aliases for writing!"));
+ return false;
+ }
+ foreach ($files_to_process as $f2p) {
+ $tmpfd = @fopen($f2p, 'r');
+ if (!$tmpfd) {
+ log_error(gettext("The following file could not be read {$f2p} from {$temp_filename}"));
+ continue;
+ }
+ while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
+ fwrite($fd, $tmpbuf);
+ }
+ fclose($tmpfd);
+ unlink($f2p);
+ }
+ fclose($fd);
+ unset($tmpbuf);
+
+ return true;
+}
+
+function version_compare_dates($a, $b) {
+ $a_time = strtotime($a);
+ $b_time = strtotime($b);
+
+ if ((!$a_time) || (!$b_time)) {
+ return FALSE;
+ } else {
+ if ($a_time < $b_time) {
+ return -1;
+ } elseif ($a_time == $b_time) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+}
+function version_get_string_value($a) {
+ $strs = array(
+ 0 => "ALPHA-ALPHA",
+ 2 => "ALPHA",
+ 3 => "BETA",
+ 4 => "B",
+ 5 => "C",
+ 6 => "D",
+ 7 => "RC",
+ 8 => "RELEASE",
+ 9 => "*" // Matches all release levels
+ );
+ $major = 0;
+ $minor = 0;
+ foreach ($strs as $num => $str) {
+ if (substr($a, 0, strlen($str)) == $str) {
+ $major = $num;
+ $n = substr($a, strlen($str));
+ if (is_numeric($n)) {
+ $minor = $n;
+ }
+ break;
+ }
+ }
+ return "{$major}.{$minor}";
+}
+function version_compare_string($a, $b) {
+ // Only compare string parts if both versions give a specific release
+ // (If either version lacks a string part, assume intended to match all release levels)
+ if (isset($a) && isset($b)) {
+ return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
+ } else {
+ return 0;
+ }
+}
+function version_compare_numeric($a, $b) {
+ $a_arr = explode('.', rtrim($a, '.0'));
+ $b_arr = explode('.', rtrim($b, '.0'));
+
+ foreach ($a_arr as $n => $val) {
+ if (array_key_exists($n, $b_arr)) {
+ // So far so good, both have values at this minor version level. Compare.
+ if ($val > $b_arr[$n]) {
+ return 1;
+ } elseif ($val < $b_arr[$n]) {
+ return -1;
+ }
+ } else {
+ // a is greater, since b doesn't have any minor version here.
+ return 1;
+ }
+ }
+ if (count($b_arr) > count($a_arr)) {
+ // b is longer than a, so it must be greater.
+ return -1;
+ } else {
+ // Both a and b are of equal length and value.
+ return 0;
+ }
+}
+function pfs_version_compare($cur_time, $cur_text, $remote) {
+ // First try date compare
+ $v = version_compare_dates($cur_time, $remote);
+ if ($v === FALSE) {
+ // If that fails, try to compare by string
+ // Before anything else, simply test if the strings are equal
+ if (($cur_text == $remote) || ($cur_time == $remote)) {
+ return 0;
+ }
+ list($cur_num, $cur_str) = explode('-', $cur_text);
+ list($rem_num, $rem_str) = explode('-', $remote);
+
+ // First try to compare the numeric parts of the version string.
+ $v = version_compare_numeric($cur_num, $rem_num);
+
+ // If the numeric parts are the same, compare the string parts.
+ if ($v == 0) {
+ return version_compare_string($cur_str, $rem_str);
+ }
+ }
+ return $v;
+}
+function process_alias_urltable($name, $url, $freq, $forceupdate=false) {
+ global $config;
+
+ $urltable_prefix = "/var/db/aliastables/";
+ $urltable_filename = $urltable_prefix . $name . ".txt";
+
+ // Make the aliases directory if it doesn't exist
+ if (!file_exists($urltable_prefix)) {
+ mkdir($urltable_prefix);
+ } elseif (!is_dir($urltable_prefix)) {
+ unlink($urltable_prefix);
+ mkdir($urltable_prefix);
+ }
+
+ // If the file doesn't exist or is older than update_freq days, fetch a new copy.
+ if (!file_exists($urltable_filename) ||
+ ((time() - filemtime($urltable_filename)) > ($freq * 86400 - 90)) ||
+ $forceupdate) {
+
+ // Try to fetch the URL supplied
+ conf_mount_rw();
+ unlink_if_exists($urltable_filename . ".tmp");
+ $verify_ssl = isset($config['system']['checkaliasesurlcert']);
+ if (download_file($url, $urltable_filename . ".tmp", $verify_ssl)) {
+ mwexec("/usr/bin/sed -E 's/\;.*//g; /^[[:space:]]*($|#)/d' ". escapeshellarg($urltable_filename . ".tmp") . " > " . escapeshellarg($urltable_filename));
+ if (alias_get_type($name) == "urltable_ports") {
+ $ports = explode("\n", str_replace("\r", "", file_get_contents($urltable_filename)));
+ $ports = group_ports($ports);
+ file_put_contents($urltable_filename, implode("\n", $ports));
+ }
+ unlink_if_exists($urltable_filename . ".tmp");
+ } else {
+ touch($urltable_filename);
+ }
+ conf_mount_ro();
+ return true;
+ } else {
+ // File exists, and it doesn't need to be updated.
+ return -1;
+ }
+}
+function get_real_slice_from_glabel($label) {
+ $label = escapeshellarg($label);
+ return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
+}
+function nanobsd_get_boot_slice() {
+ return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
+}
+function nanobsd_get_boot_drive() {
+ return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/pfsense | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' ' | /usr/bin/cut -d's' -f1`);
+}
+function nanobsd_get_active_slice() {
+ $boot_drive = nanobsd_get_boot_drive();
+ $active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
+
+ return "{$boot_drive}s{$active}";
+}
+function nanobsd_get_size() {
+ return strtoupper(file_get_contents("/etc/nanosize.txt"));
+}
+function nanobsd_switch_boot_slice() {
+ global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
+ global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
+ global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
+ nanobsd_detect_slice_info();
+
+ if ($BOOTFLASH == $ACTIVE_SLICE) {
+ $slice = $TOFLASH;
+ } else {
+ $slice = $BOOTFLASH;
+ }
+
+ for ($i = 0; $i < ob_get_level(); $i++) {
+ ob_end_flush();
+ }
+ ob_implicit_flush(1);
+ if (strstr($slice, "s2")) {
+ $ASLICE = "2";
+ $AOLDSLICE = "1";
+ $AGLABEL_SLICE = "pfsense1";
+ $AUFS_ID = "1";
+ $AOLD_UFS_ID = "0";
+ } else {
+ $ASLICE = "1";
+ $AOLDSLICE = "2";
+ $AGLABEL_SLICE = "pfsense0";
+ $AUFS_ID = "0";
+ $AOLD_UFS_ID = "1";
+ }
+ $ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
+ $ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
+ $ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
+ conf_mount_rw();
+ set_single_sysctl("kern.geom.debugflags", "16");
+ exec("gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
+ exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
+ // We can't update these if they are mounted now.
+ if ($BOOTFLASH != $slice) {
+ exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
+ nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
+ }
+ set_single_sysctl("kern.geom.debugflags", "0");
+ conf_mount_ro();
+}
+function nanobsd_clone_slice() {
+ global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
+ global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
+ global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
+ nanobsd_detect_slice_info();
+
+ for ($i = 0; $i < ob_get_level(); $i++) {
+ ob_end_flush();
+ }
+ ob_implicit_flush(1);
+ set_single_sysctl("kern.geom.debugflags", "16");
+ exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
+ exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
+ exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
+ $status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
+ set_single_sysctl("kern.geom.debugflags", "0");
+ if ($status) {
+ return false;
+ } else {
+ return true;
+ }
+}
+function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
+ $tmppath = "/tmp/{$gslice}";
+ $fstabpath = "/tmp/{$gslice}/etc/fstab";
+
+ mkdir($tmppath);
+ exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
+ exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
+ copy("/etc/fstab", $fstabpath);
+
+ if (!file_exists($fstabpath)) {
+ $fstab = <<<EOF
+/dev/ufs/{$gslice} / ufs ro,noatime 1 1
+/dev/ufs/cf /cf ufs ro,noatime 1 1
+EOF;
+ if (file_put_contents($fstabpath, $fstab)) {
+ $status = true;
+ } else {
+ $status = false;
+ }
+ } else {
+ $status = exec("sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
+ }
+ exec("/sbin/umount {$tmppath}");
+ rmdir($tmppath);
+
+ return $status;
+}
+function nanobsd_detect_slice_info() {
+ global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
+ global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
+ global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
+
+ $BOOT_DEVICE=nanobsd_get_boot_slice();
+ $REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
+ $BOOT_DRIVE=nanobsd_get_boot_drive();
+ $ACTIVE_SLICE=nanobsd_get_active_slice();
+
+ // Detect which slice is active and set information.
+ if (strstr($REAL_BOOT_DEVICE, "s1")) {
+ $SLICE = "2";
+ $OLDSLICE = "1";
+ $GLABEL_SLICE = "pfsense1";
+ $UFS_ID = "1";
+ $OLD_UFS_ID = "0";
+
+ } else {
+ $SLICE = "1";
+ $OLDSLICE = "2";
+ $GLABEL_SLICE = "pfsense0";
+ $UFS_ID = "0";
+ $OLD_UFS_ID = "1";
+ }
+ $TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
+ $COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
+ $COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
+ $BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
+}
+
+function nanobsd_friendly_slice_name($slicename) {
+ global $g;
+ return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
+}
+
+function get_include_contents($filename) {
+ if (is_file($filename)) {
+ ob_start();
+ include $filename;
+ $contents = ob_get_contents();
+ ob_end_clean();
+ return $contents;
+ }
+ return false;
+}
+
+/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
+ * it is roughly 4 times faster then our existing pfSense parser but due to the large
+ * size of the RRD xml dumps this is required.
+ * The reason we do not use it for pfSense is that it does not know about array fields
+ * which causes it to fail on array fields with single items. Possible Todo?
+ */
+function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
+ if (!function_exists('xml_parser_create')) {
+ return array ();
+ }
+ $parser = xml_parser_create('');
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+ xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
+ xml_parse_into_struct($parser, trim($contents), $xml_values);
+ xml_parser_free($parser);
+ if (!$xml_values) {
+ return; //Hmm...
+ }
+ $xml_array = array ();
+ $parents = array ();
+ $opened_tags = array ();
+ $arr = array ();
+ $current = & $xml_array;
+ $repeated_tag_index = array ();
+ foreach ($xml_values as $data) {
+ unset ($attributes, $value);
+ extract($data);
+ $result = array ();
+ $attributes_data = array ();
+ if (isset ($value)) {
+ if ($priority == 'tag') {
+ $result = $value;
+ } else {
+ $result['value'] = $value;
+ }
+ }
+ if (isset ($attributes) and $get_attributes) {
+ foreach ($attributes as $attr => $val) {
+ if ($priority == 'tag') {
+ $attributes_data[$attr] = $val;
+ } else {
+ $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
+ }
+ }
+ }
+ if ($type == "open") {
+ $parent[$level -1] = & $current;
+ if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
+ $current[$tag] = $result;
+ if ($attributes_data) {
+ $current[$tag . '_attr'] = $attributes_data;
+ }
+ $repeated_tag_index[$tag . '_' . $level] = 1;
+ $current = & $current[$tag];
+ } else {
+ if (isset ($current[$tag][0])) {
+ $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
+ $repeated_tag_index[$tag . '_' . $level]++;
+ } else {
+ $current[$tag] = array (
+ $current[$tag],
+ $result
+ );
+ $repeated_tag_index[$tag . '_' . $level] = 2;
+ if (isset ($current[$tag . '_attr'])) {
+ $current[$tag]['0_attr'] = $current[$tag . '_attr'];
+ unset ($current[$tag . '_attr']);
+ }
+ }
+ $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
+ $current = & $current[$tag][$last_item_index];
+ }
+ } elseif ($type == "complete") {
+ if (!isset ($current[$tag])) {
+ $current[$tag] = $result;
+ $repeated_tag_index[$tag . '_' . $level] = 1;
+ if ($priority == 'tag' and $attributes_data) {
+ $current[$tag . '_attr'] = $attributes_data;
+ }
+ } else {
+ if (isset ($current[$tag][0]) and is_array($current[$tag])) {
+ $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
+ if ($priority == 'tag' and $get_attributes and $attributes_data) {
+ $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
+ }
+ $repeated_tag_index[$tag . '_' . $level]++;
+ } else {
+ $current[$tag] = array (
+ $current[$tag],
+ $result
+ );
+ $repeated_tag_index[$tag . '_' . $level] = 1;
+ if ($priority == 'tag' and $get_attributes) {
+ if (isset ($current[$tag . '_attr'])) {
+ $current[$tag]['0_attr'] = $current[$tag . '_attr'];
+ unset ($current[$tag . '_attr']);
+ }
+ if ($attributes_data) {
+ $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
+ }
+ }
+ $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
+ }
+ }
+ } elseif ($type == 'close') {
+ $current = & $parent[$level -1];
+ }
+ }
+ return ($xml_array);
+}
+
+function get_country_name($country_code) {
+ if ($country_code != "ALL" && strlen($country_code) != 2) {
+ return "";
+ }
+
+ $country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
+ $country_names_contents = file_get_contents($country_names_xml);
+ $country_names = xml2array($country_names_contents);
+
+ if ($country_code == "ALL") {
+ $country_list = array();
+ foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
+ $country_list[] = array(
+ "code" => $country['ISO_3166-1_Alpha-2_Code_element'],
+ "name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
+ }
+ return $country_list;
+ }
+
+ foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
+ if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
+ return ucwords(strtolower($country['ISO_3166-1_Country_name']));
+ }
+ }
+ return "";
+}
+
+/* sort by interface only, retain the original order of rules that apply to
+ the same interface */
+function filter_rules_sort() {
+ global $config;
+
+ /* mark each rule with the sequence number (to retain the order while sorting) */
+ for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
+ $config['filter']['rule'][$i]['seq'] = $i;
+ }
+
+ usort($config['filter']['rule'], "filter_rules_compare");
+
+ /* strip the sequence numbers again */
+ for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
+ unset($config['filter']['rule'][$i]['seq']);
+ }
+}
+function filter_rules_compare($a, $b) {
+ if (isset($a['floating']) && isset($b['floating'])) {
+ return $a['seq'] - $b['seq'];
+ } else if (isset($a['floating'])) {
+ return -1;
+ } else if (isset($b['floating'])) {
+ return 1;
+ } else if ($a['interface'] == $b['interface']) {
+ return $a['seq'] - $b['seq'];
+ } else {
+ return compare_interface_friendly_names($a['interface'], $b['interface']);
+ }
+}
+
+function generate_ipv6_from_mac($mac) {
+ $elements = explode(":", $mac);
+ if (count($elements) <> 6) {
+ return false;
+ }
+
+ $i = 0;
+ $ipv6 = "fe80::";
+ foreach ($elements as $byte) {
+ if ($i == 0) {
+ $hexadecimal = substr($byte, 1, 2);
+ $bitmap = base_convert($hexadecimal, 16, 2);
+ $bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
+ $bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
+ $byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
+ }
+ $ipv6 .= $byte;
+ if ($i == 1) {
+ $ipv6 .= ":";
+ }
+ if ($i == 3) {
+ $ipv6 .= ":";
+ }
+ if ($i == 2) {
+ $ipv6 .= "ff:fe";
+ }
+
+ $i++;
+ }
+ return $ipv6;
+}
+
+/****f* pfsense-utils/load_mac_manufacturer_table
+ * NAME
+ * load_mac_manufacturer_table
+ * INPUTS
+ * none
+ * RESULT
+ * returns associative array with MAC-Manufacturer pairs
+ ******/
+function load_mac_manufacturer_table() {
+ /* load MAC-Manufacture data from the file */
+ $macs = false;
+ if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
+ $macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
+ }
+ if ($macs) {
+ foreach ($macs as $line) {
+ if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
+ /* store values like this $mac_man['000C29']='VMware' */
+ $mac_man["$matches[1]"] = $matches[2];
+ }
+ }
+ return $mac_man;
+ } else {
+ return -1;
+ }
+
+}
+
+/****f* pfsense-utils/is_ipaddr_configured
+ * NAME
+ * is_ipaddr_configured
+ * INPUTS
+ * IP Address to check.
+ * If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
+ * check_localip - if true then also check for matches with PPTP and LT2P addresses
+ * check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
+ * cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
+ * If check_subnets is true and cidrprefix is specified,
+ * then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
+ * RESULT
+ * returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
+*/
+function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
+ if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
+ return true;
+ }
+ return false;
+}
+
+/****f* pfsense-utils/where_is_ipaddr_configured
+ * NAME
+ * where_is_ipaddr_configured
+ * INPUTS
+ * IP Address to check.
+ * If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
+ * check_localip - if true then also check for matches with PPTP and LT2P addresses
+ * check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
+ * cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
+ * If check_subnets is true and cidrprefix is specified,
+ * then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
+ * RESULT
+ * Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
+ * If there are no matches then an empty array is returned.
+*/
+function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
+ global $config;
+
+ $where_configured = array();
+
+ $pos = strpos($ignore_if, '_virtualip');
+ if ($pos !== false) {
+ $ignore_vip_id = substr($ignore_if, $pos+10);
+ $ignore_vip_if = substr($ignore_if, 0, $pos);
+ } else {
+ $ignore_vip_id = -1;
+ $ignore_vip_if = $ignore_if;
+ }
+
+ $isipv6 = is_ipaddrv6($ipaddr);
+
+ if ($check_subnets) {
+ $cidrprefix = intval($cidrprefix);
+ if ($isipv6) {
+ if (($cidrprefix < 1) || ($cidrprefix > 128)) {
+ $cidrprefix = 128;
+ }
+ } else {
+ if (($cidrprefix < 1) || ($cidrprefix > 32)) {
+ $cidrprefix = 32;
+ }
+ }
+ $iflist = get_configured_interface_list();
+ foreach ($iflist as $if => $ifname) {
+ if ($ignore_if == $if) {
+ continue;
+ }
+
+ if ($isipv6) {
+ $if_ipv6 = get_interface_ipv6($if);
+ $if_snbitsv6 = get_interface_subnetv6($if);
+ if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
+ $where_entry = array();
+ $where_entry['if'] = $if;
+ $where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
+ $where_configured[] = $where_entry;
+ }
+ } else {
+ $if_ipv4 = get_interface_ip($if);
+ $if_snbitsv4 = get_interface_subnet($if);
+ if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
+ $where_entry = array();
+ $where_entry['if'] = $if;
+ $where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
+ $where_configured[] = $where_entry;
+ }
+ }
+ }
+ } else {
+ if ($isipv6) {
+ $interface_list_ips = get_configured_ipv6_addresses();
+ } else {
+ $interface_list_ips = get_configured_ip_addresses();
+ }
+
+ foreach ($interface_list_ips as $if => $ilips) {
+ if ($ignore_if == $if) {
+ continue;
+ }
+ if (strcasecmp($ipaddr, $ilips) == 0) {
+ $where_entry = array();
+ $where_entry['if'] = $if;
+ $where_entry['ip_or_subnet'] = $ilips;
+ $where_configured[] = $where_entry;
+ }
+ }
+ }
+
+ $interface_list_vips = get_configured_vips_list(true);
+ foreach ($interface_list_vips as $id => $vip) {
+ /* Skip CARP interfaces here since they were already checked above */
+ if ($id == $ignore_vip_id || (substr($ignore_if, 0, 4) == '_vip') && substr($ignore_vip_if, 5) == $vip['uniqdid']) {
+ continue;
+ }
+ if (strcasecmp($ipaddr, $vip['ipaddr']) == 0) {
+ $where_entry = array();
+ $where_entry['if'] = $vip['if'];
+ $where_entry['ip_or_subnet'] = $vip['ipaddr'];
+ $where_configured[] = $where_entry;
+ }
+ }
+
+ if ($check_localip) {
+ if (is_array($config['pptpd']) && !empty($config['pptpd']['localip']) && (strcasecmp($ipaddr, $config['pptpd']['localip']) == 0)) {
+ $where_entry = array();
+ $where_entry['if'] = 'pptp';
+ $where_entry['ip_or_subnet'] = $config['pptpd']['localip'];
+ $where_configured[] = $where_entry;
+ }
+
+ if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
+ $where_entry = array();
+ $where_entry['if'] = 'l2tp';
+ $where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
+ $where_configured[] = $where_entry;
+ }
+ }
+
+ return $where_configured;
+}
+
+/****f* pfsense-utils/pfSense_handle_custom_code
+ * NAME
+ * pfSense_handle_custom_code
+ * INPUTS
+ * directory name to process
+ * RESULT
+ * globs the directory and includes the files
+ */
+function pfSense_handle_custom_code($src_dir) {
+ // Allow extending of the nat edit page and include custom input validation
+ if (is_dir("$src_dir")) {
+ $cf = glob($src_dir . "/*.inc");
+ foreach ($cf as $nf) {
+ if ($nf == "." || $nf == "..") {
+ continue;
+ }
+ // Include the extra handler
+ include("$nf");
+ }
+ }
+}
+
+function set_language($lang = 'en_US', $encoding = "UTF-8") {
+ putenv("LANG={$lang}.{$encoding}");
+ setlocale(LC_ALL, "{$lang}.{$encoding}");
+ textdomain("pfSense");
+ bindtextdomain("pfSense", "/usr/local/share/locale");
+ bind_textdomain_codeset("pfSense", "{$lang}.{$encoding}");
+}
+
+function get_locale_list() {
+ $locales = array(
+ "en_US" => gettext("English"),
+ "pt_BR" => gettext("Portuguese (Brazil)"),
+ "tr" => gettext("Turkish"),
+ );
+ asort($locales);
+ return $locales;
+}
+
+function system_get_language_code() {
+ global $config, $g_languages;
+
+ // a language code, as per [RFC3066]
+ $language = $config['system']['language'];
+ //$code = $g_languages[$language]['code'];
+ $code = str_replace("_", "-", $language);
+
+ if (empty($code)) {
+ $code = "en-US"; // Set default code.
+ }
+
+ return $code;
+}
+
+function system_get_language_codeset() {
+ global $config, $g_languages;
+
+ $language = $config['system']['language'];
+ $codeset = $g_languages[$language]['codeset'];
+
+ if (empty($codeset)) {
+ $codeset = "UTF-8"; // Set default codeset.
+ }
+
+ return $codeset;
+}
+
+/* Available languages/locales */
+$g_languages = array (
+ "sq" => array("codeset" => "UTF-8", "desc" => gettext("Albanian")),
+ "bg" => array("codeset" => "UTF-8", "desc" => gettext("Bulgarian")),
+ "zh_CN" => array("codeset" => "UTF-8", "desc" => gettext("Chinese (Simplified)")),
+ "zh_TW" => array("codeset" => "UTF-8", "desc" => gettext("Chinese (Traditional)")),
+ "nl" => array("codeset" => "UTF-8", "desc" => gettext("Dutch")),
+ "da" => array("codeset" => "UTF-8", "desc" => gettext("Danish")),
+ "en_US" => array("codeset" => "UTF-8", "desc" => gettext("English")),
+ "fi" => array("codeset" => "UTF-8", "desc" => gettext("Finnish")),
+ "fr" => array("codeset" => "UTF-8", "desc" => gettext("French")),
+ "de" => array("codeset" => "UTF-8", "desc" => gettext("German")),
+ "el" => array("codeset" => "UTF-8", "desc" => gettext("Greek")),
+ "hu" => array("codeset" => "UTF-8", "desc" => gettext("Hungarian")),
+ "it" => array("codeset" => "UTF-8", "desc" => gettext("Italian")),
+ "ja" => array("codeset" => "UTF-8", "desc" => gettext("Japanese")),
+ "ko" => array("codeset" => "UTF-8", "desc" => gettext("Korean")),
+ "lv" => array("codeset" => "UTF-8", "desc" => gettext("Latvian")),
+ "nb" => array("codeset" => "UTF-8", "desc" => gettext("Norwegian (Bokmal)")),
+ "pl" => array("codeset" => "UTF-8", "desc" => gettext("Polish")),
+ "pt_BR" => array("codeset" => "UTF-8", "desc" => gettext("Portuguese (Brazil)")),
+ "pt" => array("codeset" => "UTF-8", "desc" => gettext("Portuguese (Portugal)")),
+ "ro" => array("codeset" => "UTF-8", "desc" => gettext("Romanian")),
+ "ru" => array("codeset" => "UTF-8", "desc" => gettext("Russian")),
+ "sl" => array("codeset" => "UTF-8", "desc" => gettext("Slovenian")),
+ "tr" => array("codeset" => "UTF-8", "desc" => gettext("Turkish")),
+ "es" => array("codeset" => "UTF-8", "desc" => gettext("Spanish")),
+ "sv" => array("codeset" => "UTF-8", "desc" => gettext("Swedish")),
+ "sk" => array("codeset" => "UTF-8", "desc" => gettext("Slovak")),
+ "cs" => array("codeset" => "UTF-8", "desc" => gettext("Czech"))
+);
+
+function return_hex_ipv4($ipv4) {
+ if (!is_ipaddrv4($ipv4)) {
+ return(false);
+ }
+
+ /* we need the hex form of the interface IPv4 address */
+ $ip4arr = explode(".", $ipv4);
+ return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
+}
+
+function convert_ipv6_to_128bit($ipv6) {
+ if (!is_ipaddrv6($ipv6)) {
+ return(false);
+ }
+
+ $ip6arr = array();
+ $ip6prefix = Net_IPv6::uncompress($ipv6);
+ $ip6arr = explode(":", $ip6prefix);
+ /* binary presentation of the prefix for all 128 bits. */
+ $ip6prefixbin = "";
+ foreach ($ip6arr as $element) {
+ $ip6prefixbin .= sprintf("%016b", hexdec($element));
+ }
+ return($ip6prefixbin);
+}
+
+function convert_128bit_to_ipv6($ip6bin) {
+ if (strlen($ip6bin) <> 128) {
+ return(false);
+ }
+
+ $ip6arr = array();
+ $ip6binarr = array();
+ $ip6binarr = str_split($ip6bin, 16);
+ foreach ($ip6binarr as $binpart) {
+ $ip6arr[] = dechex(bindec($binpart));
+ }
+ $ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
+
+ return($ip6addr);
+}
+
+
+/* Returns the calculated bit length of the prefix delegation from the WAN interface */
+/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
+/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
+/* 6to4 is 16 bits, e.g. 65535 */
+function calculate_ipv6_delegation_length($if) {
+ global $config;
+
+ if (!is_array($config['interfaces'][$if])) {
+ return false;
+ }
+
+ switch ($config['interfaces'][$if]['ipaddrv6']) {
+ case "6to4":
+ $pdlen = 16;
+ break;
+ case "6rd":
+ $rd6cfg = $config['interfaces'][$if];
+ $rd6plen = explode("/", $rd6cfg['prefix-6rd']);
+ $pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
+ break;
+ case "dhcp6":
+ $dhcp6cfg = $config['interfaces'][$if];
+ $pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
+ break;
+ default:
+ $pdlen = 0;
+ break;
+ }
+ return($pdlen);
+}
+
+function huawei_rssi_to_string($rssi) {
+ $dbm = array();
+ $i = 0;
+ $dbstart = -113;
+ while ($i < 32) {
+ $dbm[$i] = $dbstart + ($i * 2);
+ $i++;
+ }
+ $percent = round(($rssi / 31) * 100);
+ $string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
+ return $string;
+}
+
+function huawei_mode_to_string($mode, $submode) {
+ $modes[0] = "None";
+ $modes[1] = "AMPS";
+ $modes[2] = "CDMA";
+ $modes[3] = "GSM/GPRS";
+ $modes[4] = "HDR";
+ $modes[5] = "WCDMA";
+ $modes[6] = "GPS";
+
+ $submodes[0] = "No Service";
+ $submodes[1] = "GSM";
+ $submodes[2] = "GPRS";
+ $submodes[3] = "EDGE";
+ $submodes[4] = "WCDMA";
+ $submodes[5] = "HSDPA";
+ $submodes[6] = "HSUPA";
+ $submodes[7] = "HSDPA+HSUPA";
+ $submodes[8] = "TD-SCDMA";
+ $submodes[9] = "HSPA+";
+ $string = "{$modes[$mode]}, {$submodes[$submode]} Mode";
+ return $string;
+}
+
+function huawei_service_to_string($state) {
+ $modes[0] = "No";
+ $modes[1] = "Restricted";
+ $modes[2] = "Valid";
+ $modes[3] = "Restricted Regional";
+ $modes[4] = "Powersaving";
+ $string = "{$modes[$state]} Service";
+ return $string;
+}
+
+function huawei_simstate_to_string($state) {
+ $modes[0] = "Invalid SIM/locked";
+ $modes[1] = "Valid SIM";
+ $modes[2] = "Invalid SIM CS";
+ $modes[3] = "Invalid SIM PS";
+ $modes[4] = "Invalid SIM CS/PS";
+ $modes[255] = "Missing SIM";
+ $string = "{$modes[$state]} State";
+ return $string;
+}
+
+function zte_rssi_to_string($rssi) {
+ return huawei_rssi_to_string($rssi);
+}
+
+function zte_mode_to_string($mode, $submode) {
+ $modes[0] = "No Service";
+ $modes[1] = "Limited Service";
+ $modes[2] = "GPRS";
+ $modes[3] = "GSM";
+ $modes[4] = "UMTS";
+ $modes[5] = "EDGE";
+ $modes[6] = "HSDPA";
+
+ $submodes[0] = "CS_ONLY";
+ $submodes[1] = "PS_ONLY";
+ $submodes[2] = "CS_PS";
+ $submodes[3] = "CAMPED";
+ $string = "{$modes[$mode]}, {$submodes[$submode]} Mode";
+ return $string;
+}
+
+function zte_service_to_string($state) {
+ $modes[0] = "Initializing";
+ $modes[1] = "Network Lock error";
+ $modes[2] = "Network Locked";
+ $modes[3] = "Unlocked or correct MCC/MNC";
+ $string = "{$modes[$state]} Service";
+ return $string;
+}
+
+function zte_simstate_to_string($state) {
+ $modes[0] = "No action";
+ $modes[1] = "Network lock";
+ $modes[2] = "(U)SIM card lock";
+ $modes[3] = "Network Lock and (U)SIM card Lock";
+ $string = "{$modes[$state]} State";
+ return $string;
+}
+
+function get_configured_pppoe_server_interfaces() {
+ global $config;
+ $iflist = array();
+ if (is_array($config['pppoes']['pppoe'])) {
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ if ($pppoe['mode'] == "server") {
+ $int = "poes". $pppoe['pppoeid'];
+ $iflist[$int] = strtoupper($int);
+ }
+ }
+ }
+ return $iflist;
+}
+
+function get_pppoes_child_interfaces($ifpattern) {
+ $if_arr = array();
+ if ($ifpattern == "") {
+ return;
+ }
+
+ exec("ifconfig", $out, $ret);
+ foreach ($out as $line) {
+ if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
+ $if_arr[] = $match[1];
+ }
+ }
+ return $if_arr;
+
+}
+
+/****f* pfsense-utils/pkg_call_plugins
+ * NAME
+ * pkg_call_plugins
+ * INPUTS
+ * $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
+ * $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
+ * RESULT
+ * returns associative array results from the plugin calls for each package
+ * NOTES
+ * This generic function can be used to notify or retrieve results from functions that are defined in packages.
+ ******/
+function pkg_call_plugins($plugin_type, $plugin_params) {
+ global $g, $config;
+ $results = array();
+ if (!is_array($config['installedpackages']['package'])) {
+ return $results;
+ }
+ foreach ($config['installedpackages']['package'] as $package) {
+ if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
+ continue;
+ }
+ $pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
+ $pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
+ if (is_array($pkg_config['plugins']['item'])) {
+ foreach ($pkg_config['plugins']['item'] as $plugin) {
+ if ($plugin['type'] == $plugin_type) {
+ if (file_exists($pkg_config['include_file'])) {
+ require_once($pkg_config['include_file']);
+ } else {
+ continue;
+ }
+ $plugin_function = $pkgname . '_'. $plugin_type;
+ $results[$pkgname] = call_user_func($plugin_function, $plugin_params);
+ }
+ }
+ }
+ }
+ return $results;
+}
+
+/* Function to find and return the active XML RPC base URL to avoid code duplication */
+function get_active_xml_rpc_base_url() {
+ global $config, $g;
+ /* If the user has activated the option to enable an alternate xmlrpcbaseurl, and it's not empty, then use it */
+ if (isset($config['system']['altpkgrepo']['enable']) && !empty($config['system']['altpkgrepo']['xmlrpcbaseurl'])) {
+ return $config['system']['altpkgrepo']['xmlrpcbaseurl'];
+ } else {
+ return $g['xmlrpcbaseurl'];
+ }
+}
+
+?>
diff --git a/src/etc/inc/pkg-utils.inc b/src/etc/inc/pkg-utils.inc
new file mode 100644
index 0000000..54c018d
--- /dev/null
+++ b/src/etc/inc/pkg-utils.inc
@@ -0,0 +1,953 @@
+<?php
+/****h* pfSense/pkg-utils
+ NAME
+ pkg-utils.inc - Package subsystem
+ DESCRIPTION
+ This file contains various functions used by the pfSense package system.
+ HISTORY
+ $Id$
+
+ Copyright (C) 2010 Ermal Luçi
+ Copyright (C) 2005-2006 Colin Smith (ethethlay@gmail.com)
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/bin/cd /usr/bin/tar /usr/sbin/fifolog_create /bin/chmod
+ pfSense_BUILDER_BINARIES: /usr/sbin/pkg_add /usr/sbin/pkg_info /usr/sbin/pkg_delete /bin/rm
+ pfSense_MODULE: pkg
+*/
+
+require_once("globals.inc");
+require_once("service-utils.inc");
+
+if (file_exists("/cf/conf/use_xmlreader")) {
+ require_once("xmlreader.inc");
+} else {
+ require_once("xmlparse.inc");
+}
+
+require_once("pfsense-utils.inc");
+
+if (!function_exists("pkg_debug")) {
+ /* set up logging if needed */
+ function pkg_debug($msg) {
+ global $g, $debug, $fd_log;
+
+ if (!$debug) {
+ return;
+ }
+
+ if (!$fd_log) {
+ if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_debug.log", "w")) {
+ update_output_window("Warning, could not open log for writing.");
+ }
+ }
+ @fwrite($fd_log, $msg);
+ }
+}
+
+global $g;
+if (!isset($g['platform'])) {
+ $g['platform'] = trim(file_get_contents("/etc/platform"));
+}
+
+/* Remove pkg_prefix from package name if it's present */
+function pkg_remove_prefix(&$pkg_name) {
+ global $g;
+
+ if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
+ $pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
+ }
+}
+
+/* Execute a pkg call */
+function pkg_call($params, $mute = false) {
+ global $static_output, $g, $config;
+
+ if (empty($params)) {
+ return false;
+ }
+
+ $user_agent = $g['product_name'] . '/' . $g['product_version'];
+ if (!isset($config['system']['host_uuid'])) {
+ $user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
+ }
+
+ $env = array(
+ "HTTP_USER_AGENT" => $user_agent,
+ "ASSUME_ALWAYS_YES" => "true"
+ );
+
+ $debug_fifo = $g['tmp_path'] . "/pkg-debug.fifo";
+ if (!file_exists($debug_fifo)) {
+ posix_mkfifo($debug_fifo, 0600);
+ }
+
+ if (filetype($debug_fifo) == 'fifo') {
+ $env["EVENT_PIPE"] = $debug_fifo;
+ }
+
+ $descriptorspec = array(
+ 1 => array("pipe", "w"), /* stdout */
+ 2 => array("pipe", "w") /* stderr */
+ );
+
+ pkg_debug("pkg_call(): {$params}\n");
+ $process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes, '/', $env);
+
+ if (!is_resource($process)) {
+ return false;
+ }
+
+ stream_set_blocking($pipes[1], 0);
+ stream_set_blocking($pipes[2], 0);
+
+ /* XXX: should be a tunnable? */
+ $timeout = 300; // seconds
+ $error_log = '';
+
+ do {
+ $write = array();
+ $read = array($pipes[1], $pipes[2]);
+ $except = array();
+
+ $stream = stream_select($read, $write, $except, null, $timeout);
+ if ($stream !== FALSE && $stream > 0) {
+ foreach ($read as $pipe) {
+ $content = stream_get_contents($pipe);
+ if ($content == '') {
+ continue;
+ }
+ if ($pipe === $pipes[1]) {
+ if (!$mute) {
+ $static_output .= $content;
+ update_output_window($static_output);
+ }
+ flush();
+ } else if ($pipe === $pipes[2]) {
+ $error_log .= $content;
+ }
+ }
+ }
+ $status = proc_get_status($process);
+ } while ($status['running']);
+ fclose($pipes[1]);
+ fclose($pipes[2]);
+ proc_close($process);
+
+ $rc = $status['exitcode'];
+
+ pkg_debug("pkg_call(): rc = {$rc}\n");
+ if ($rc == 0) {
+ return true;
+ }
+
+ pkg_debug("pkg_call(): error_log\n{$error_log}\n");
+ if (!$mute) {
+ $static_output .= "\n\n" . sprintf(gettext("ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"), $rc, $params) . "\n" . $error_log;
+ update_output_window($static_output);
+ }
+ return false;
+}
+
+/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
+function pkg_exec($params, &$stdout, &$stderr) {
+ global $g, $config;
+
+ if (empty($params)) {
+ return -1;
+ }
+
+ $user_agent = $g['product_name'] . '/' . $g['product_version'];
+ if (!isset($config['system']['host_uuid'])) {
+ $user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
+ }
+
+ $env = array(
+ "HTTP_USER_AGENT" => $user_agent,
+ "ASSUME_ALWAYS_YES" => "true"
+ );
+
+ $debug_fifo = $g['tmp_path'] . "/pkg-debug.fifo";
+ if (!file_exists($debug_fifo)) {
+ posix_mkfifo($debug_fifo, 0600);
+ }
+
+ if (filetype($debug_fifo) == 'fifo') {
+ $env["EVENT_PIPE"] = $debug_fifo;
+ }
+
+ $descriptorspec = array(
+ 1 => array("pipe", "w"), /* stdout */
+ 2 => array("pipe", "w") /* stderr */
+ );
+
+ pkg_debug("pkg_exec(): {$params}\n");
+ $process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes, '/', $env);
+
+ if (!is_resource($process)) {
+ return -1;
+ }
+
+ $stdout = '';
+ while (($l = fgets($pipes[1])) !== FALSE) {
+ $stdout .= $l;
+ }
+ fclose($pipes[1]);
+
+ $stderr = '';
+ while (($l = fgets($pipes[2])) !== FALSE) {
+ $stderr .= $l;
+ }
+ fclose($pipes[2]);
+
+ return proc_close($process);
+}
+
+/* Check if package is installed */
+function is_pkg_installed($pkg_name) {
+ global $g;
+
+ pkg_remove_prefix($pkg_name);
+
+ return pkg_call("info -e " . $g['pkg_prefix'] . $pkg_name, true);
+}
+
+/* Install package, $pkg_name should not contain prefix */
+function pkg_install($pkg_name) {
+ global $g;
+ $result = false;
+
+ pkg_remove_prefix($pkg_name);
+
+ pkg_debug("Installing package {$pkg_name}\n");
+ if (!is_pkg_installed($pkg_name)) {
+ $result = pkg_call("install -y " . $g['pkg_prefix'] . $pkg_name);
+ /* Cleanup cacke to free disk space */
+ pkg_call("clean -y");
+ }
+
+ return $result;
+}
+
+/* Delete package from FreeBSD, $pkg_name should not contain prefix */
+function pkg_delete($pkg_name) {
+ global $g;
+
+ pkg_remove_prefix($pkg_name);
+
+ pkg_debug("Removing package {$pkg_name}\n");
+ if (is_pkg_installed($pkg_name)) {
+ pkg_call("delete -y " . $g['pkg_prefix'] . $pkg_name);
+ /* Cleanup unecessary dependencies */
+ pkg_call("autoremove -y");
+ }
+}
+
+/* Check if package is present in config.xml */
+function is_package_installed($package_name) {
+ return (get_package_id($package_name) != -1);
+}
+
+/* Find package array index */
+function get_package_id($package_name) {
+ global $config;
+
+ if (!is_array($config['installedpackages']['package'])) {
+ return -1;
+ }
+
+ foreach ($config['installedpackages']['package'] as $idx => $pkg) {
+ if ($pkg['name'] == $package_name) {
+ return $idx;
+ }
+ }
+
+ return -1;
+}
+
+/* Keep backward compatibility since snort/suricata use this function */
+function get_pkg_id($package_name) {
+ return get_package_id($package_name);
+}
+
+/* Return internal_name when it's defined, otherwise, returns name */
+function get_package_internal_name($package_data) {
+ if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
+ /* e.g. name is Ipguard-dev, internal name is ipguard */
+ return $package_data['internal_name'];
+ } else {
+ return $package_data['name'];
+ }
+}
+
+/* Get information about packages */
+function get_pkg_info($pkgs = 'all', $info = 'all') {
+ global $g, $static_output;
+
+ $out = '';
+ $err = '';
+
+ if ($pkgs == 'all') {
+ $pkgs = $g['pkg_prefix'];
+ }
+
+ /* Make sure repo metadata is up2date */
+ $static_output .= "\n" . gettext("Updating package repository metadada...") . "\n";
+ update_status($static_output);
+ if (!pkg_call("update")) {
+ $static_output .= "\n" . gettext("ERROR: An error occurred when updating packages repository. Aborting...") . "\n";
+ update_status($static_output);
+ return array();
+ }
+
+ $rc = pkg_exec("search -U --raw-format json-compact " . $pkgs, $out, $err);
+
+ if ($rc != 0) {
+ $static_output .= "\n" . gettext("ERROR: Error trying to get packages list. Aborting...") . "\n";
+ $static_output .= $err;
+ update_status($static_output);
+ return array();
+ }
+
+ $result = array();
+ $pkgs_info = explode("\n", $out);
+ foreach ($pkgs_info as $pkg_info_json) {
+ $pkg_info = json_decode($pkg_info_json, true);
+ if (!isset($pkg_info['name'])) {
+ continue;
+ }
+
+ $result[] = $pkg_info;
+ unset($pkg_info);
+ }
+
+ return $result;
+}
+
+/*
+ * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
+ * This function may also print output to the terminal indicating progress.
+ */
+function resync_all_package_configs($show_message = false) {
+ global $config, $pkg_interface, $g;
+
+ log_error(gettext("Resyncing configuration for all packages."));
+
+ if (!is_array($config['installedpackages']['package'])) {
+ return;
+ }
+
+ if ($show_message == true) {
+ echo "Syncing packages:";
+ }
+
+ conf_mount_rw();
+
+ foreach ($config['installedpackages']['package'] as $idx => $package) {
+ if (empty($package['name'])) {
+ continue;
+ }
+ if ($show_message == true) {
+ echo " " . $package['name'];
+ }
+ if (platform_booting() != true) {
+ stop_service(get_package_internal_name($package));
+ }
+ sync_package($package['name']);
+ if ($pkg_interface == "console") {
+ echo "\n" . gettext("Syncing packages:");
+ }
+ }
+
+ if ($show_message == true) {
+ echo " done.\n";
+ }
+
+ @unlink("/conf/needs_package_sync");
+ conf_mount_ro();
+}
+
+function uninstall_package($package_name) {
+ global $config, $static_output;
+
+ $internal_name = $package_name;
+ $id = get_package_id($package_name);
+ if ($id >= 0) {
+ $internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
+ stop_service($internal_name);
+ }
+
+ if (is_pkg_installed($internal_name)) {
+ $static_output .= "Removing package...\n";
+ update_output_window($static_output);
+ pkg_delete($internal_name);
+ } else {
+ delete_package_xml($package_name);
+ }
+
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+}
+
+/* Run <custom_php_resync_config_command> */
+function sync_package($package_name) {
+ global $config, $builder_package_install;
+
+ // If this code is being called by pfspkg_installer
+ // which the builder system uses then return (ignore).
+ if ($builder_package_install) {
+ return;
+ }
+
+ if (empty($config['installedpackages']['package'])) {
+ return;
+ }
+
+ if (($pkg_id = get_package_id($package_name)) == -1) {
+ return; // This package doesn't really exist - exit the function.
+ }
+
+ if (!is_array($config['installedpackages']['package'][$pkg_id])) {
+ return; // No package belongs to the pkg_id passed to this function.
+ }
+
+ $package =& $config['installedpackages']['package'][$pkg_id];
+ if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
+ log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
+ delete_package_xml($package['name']);
+ return;
+ }
+
+ $pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
+ if (isset($pkg_config['nosync'])) {
+ return;
+ }
+
+ /* Bring in package include files */
+ if (!empty($pkg_config['include_file'])) {
+ $include_file = $pkg_config['include_file'];
+ if (file_exists($include_file)) {
+ require_once($include_file);
+ } else {
+ log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
+ uninstall_package($package['name']);
+ if (install_package($package['name']) != 0) {
+ log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
+ return;
+ }
+ if (file_exists($include_file)) {
+ require_once($include_file);
+ } else {
+ return;
+ }
+ }
+ }
+
+ if (!empty($pkg_config['custom_php_global_functions'])) {
+ eval($pkg_config['custom_php_global_functions']);
+ }
+ if (!empty($pkg_config['custom_php_resync_config_command'])) {
+ eval($pkg_config['custom_php_resync_config_command']);
+ }
+}
+
+/* Read info.xml installed by package and return an array */
+function read_package_config($package_name) {
+ global $g;
+
+ $pkg_info_xml = '/usr/local/share/' . $g['pkg_prefix'] . $package_name . '/info.xml';
+
+ if (!file_exists($pkg_info_xml)) {
+ return false;
+ }
+
+ $pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
+
+ if (empty($pkg_info)) {
+ return false;
+ }
+
+ /* it always returns an array with 1 item */
+ return $pkg_info['package'][0];
+}
+
+function get_after_install_info($package_name) {
+ $pkg_config = read_package_config($package_name);
+
+ if (isset($pkg_config['after_install_info'])) {
+ return $pkg_config['after_install_info'];
+ }
+
+ return '';
+}
+
+function eval_once($toeval) {
+ global $evaled;
+ if (!$evaled) {
+ $evaled = array();
+ }
+ $evalmd5 = md5($toeval);
+ if (!in_array($evalmd5, $evaled)) {
+ @eval($toeval);
+ $evaled[] = $evalmd5;
+ }
+ return;
+}
+
+function install_package($package_name) {
+ global $g, $config, $static_output, $pkg_interface;
+
+ if ($pkg_interface == "console") {
+ echo "\n";
+ }
+
+ return pkg_install($package_name);
+}
+
+function install_package_xml($package_name) {
+ global $g, $config, $static_output, $pkg_interface;
+
+ if ($pkg_interface == "console") {
+ echo "\n";
+ }
+
+ if (($pkg_info = read_package_config($package_name)) == false) {
+ return false;
+ }
+
+ /* safe side. Write config below will send to ro again. */
+ conf_mount_rw();
+
+ pkg_debug(gettext("Beginning package installation.") . "\n");
+ log_error(sprintf(gettext('Beginning package installation for %s .'), $pkg_info['name']));
+ $static_output .= sprintf(gettext("Beginning package installation for %s .\n"), $pkg_info['name']);
+ update_status($static_output);
+
+ /* add package information to config.xml */
+ $pkgid = get_package_id($pkg_info['name']);
+ $static_output .= gettext("Saving updated package information...") . " ";
+ update_output_window($static_output);
+ if ($pkgid == -1) {
+ $config['installedpackages']['package'][] = $pkg_info;
+ $changedesc = sprintf(gettext("Installed %s package."), $pkg_info['name']);
+ $to_output = gettext("done.") . "\n";
+ } else {
+ $config['installedpackages']['package'][$pkgid] = $pkg_info;
+ $changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
+ $to_output = gettext("overwrite!") . "\n";
+ }
+ unlink_if_exists('/conf/needs_package_sync');
+ conf_mount_ro();
+ write_config("Intermediate config write during package install for {$pkg_info['name']}.");
+ $static_output .= $to_output;
+ update_output_window($static_output);
+
+ if (($pkgid = get_package_id($package_name)) == -1) {
+ $static_output .= sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $package_name, "\n\n");
+ update_output_window($static_output);
+ if ($pkg_interface <> "console") {
+ echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
+ echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
+ }
+
+ uninstall_package($package_name);
+ write_config($changedesc);
+ log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
+ $static_output .= gettext("Failed to install package.") . "\n";
+ update_output_window($static_output);
+ return false;
+ }
+
+ $configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
+ if (file_exists("/usr/local/pkg/" . $configfile)) {
+ $static_output .= gettext("Loading package configuration... ");
+ update_output_window($static_output);
+ $pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ $static_output .= gettext("Configuring package components...\n");
+ if (!empty($pkg_config['filter_rules_needed'])) {
+ $config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
+ }
+ update_output_window($static_output);
+ /* modify system files */
+
+ /* if a require exists, include it. this will
+ * show us where an error exists in a package
+ * instead of making us blindly guess
+ */
+ $missing_include = false;
+ if ($pkg_config['include_file'] <> "") {
+ $static_output .= gettext("Loading package instructions...") . "\n";
+ update_output_window($static_output);
+ if (file_exists($pkg_config['include_file'])) {
+ pkg_debug("require_once('{$pkg_config['include_file']}')\n");
+ require_once($pkg_config['include_file']);
+ } else {
+ pkg_debug("Missing include {$pkg_config['include_file']}\n");
+ $missing_include = true;
+ $static_output .= "Include " . basename($pkg_config['include_file']) . " is missing!\n";
+ update_output_window($static_output);
+
+ uninstall_package($package_name);
+ write_config($changedesc);
+ log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
+ $static_output .= gettext("Failed to install package.") . "\n";
+ update_output_window($static_output);
+ return false;
+ }
+ }
+
+ /* custom commands */
+ $static_output .= gettext("Custom commands...") . "\n";
+ update_output_window($static_output);
+ if ($missing_include == false) {
+ if ($pkg_config['custom_php_global_functions'] <> "") {
+ $static_output .= gettext("Executing custom_php_global_functions()...");
+ update_output_window($static_output);
+ eval_once($pkg_config['custom_php_global_functions']);
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ if ($pkg_config['custom_php_install_command']) {
+ $static_output .= gettext("Executing custom_php_install_command()...");
+ update_output_window($static_output);
+ eval_once($pkg_config['custom_php_install_command']);
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ if ($pkg_config['custom_php_resync_config_command'] <> "") {
+ $static_output .= gettext("Executing custom_php_resync_config_command()...");
+ update_output_window($static_output);
+ eval_once($pkg_config['custom_php_resync_config_command']);
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ }
+ /* sidebar items */
+ if (is_array($pkg_config['menu'])) {
+ $static_output .= gettext("Menu items... ");
+ update_output_window($static_output);
+ foreach ($pkg_config['menu'] as $menu) {
+ if (is_array($config['installedpackages']['menu'])) {
+ foreach ($config['installedpackages']['menu'] as $amenu) {
+ if ($amenu['name'] == $menu['name']) {
+ continue 2;
+ }
+ }
+ } else {
+ $config['installedpackages']['menu'] = array();
+ }
+ $config['installedpackages']['menu'][] = $menu;
+ }
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ /* services */
+ if (is_array($pkg_config['service'])) {
+ $static_output .= gettext("Services... ");
+ update_output_window($static_output);
+ foreach ($pkg_config['service'] as $service) {
+ if (is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $aservice) {
+ if ($aservice['name'] == $service['name']) {
+ continue 2;
+ }
+ }
+ } else {
+ $config['installedpackages']['service'] = array();
+ }
+ $config['installedpackages']['service'][] = $service;
+ }
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ } else {
+ pkg_debug("Unable to find config file\n");
+ $static_output .= gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted.");
+ update_output_window($static_output);
+ pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
+ if ($pkg_interface <> "console") {
+ echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
+ echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
+ }
+
+ uninstall_package($package_name);
+ write_config($changedesc);
+ log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
+ $static_output .= gettext("Failed to install package.") . "\n";
+ update_output_window($static_output);
+ return false;
+ }
+
+ /* set up package logging streams */
+ if ($pkg_info['logging']) {
+ system_syslogd_start();
+ }
+
+ $static_output .= gettext("Writing configuration... ");
+ update_output_window($static_output);
+ write_config($changedesc);
+ log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ if ($pkg_info['after_install_info']) {
+ update_output_window($pkg_info['after_install_info']);
+ }
+
+ return true;
+}
+
+function delete_package($package_name) {
+ global $config, $g, $static_output;
+
+ if (!is_package_installed($package_name)) {
+ return;
+ }
+
+ $static_output .= sprintf(gettext("Starting package deletion for %s..."), $package_name);
+ update_output_window($static_output);
+
+ pkg_delete($package_name);
+ $static_output .= "done.\n";
+ update_output_window($static_output);
+
+ return;
+}
+
+function delete_package_xml($package_name, $when = "post-deinstall") {
+ global $g, $config, $static_output, $pkg_interface;
+
+ conf_mount_rw();
+
+ $pkgid = get_package_id($package_name);
+ if ($pkgid == -1) {
+ $static_output .= sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $package_name, "\n\n");
+ update_output_window($static_output);
+ if ($pkg_interface <> "console") {
+ echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
+ echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
+ }
+ ob_flush();
+ sleep(1);
+ conf_mount_ro();
+ return;
+ }
+ pkg_debug(sprintf(gettext("Removing %s package... "), $package_name));
+ $static_output .= sprintf(gettext("Removing %s components..."), $package_name) . "\n";
+ update_output_window($static_output);
+ /* parse package configuration */
+ $packages = &$config['installedpackages']['package'];
+ $menus =& $config['installedpackages']['menu'];
+ $services = &$config['installedpackages']['service'];
+ $pkg_info =& $packages[$pkgid];
+ if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
+ $pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
+ /* remove menu items */
+ if (is_array($pkg_config['menu'])) {
+ $static_output .= gettext("Menu items... ");
+ update_output_window($static_output);
+ if (is_array($pkg_config['menu']) && is_array($menus)) {
+ foreach ($pkg_config['menu'] as $menu) {
+ foreach ($menus as $key => $instmenu) {
+ if ($instmenu['name'] == $menu['name']) {
+ unset($menus[$key]);
+ break;
+ }
+ }
+ }
+ }
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ /* remove services */
+ if (is_array($pkg_config['service'])) {
+ $static_output .= gettext("Services... ");
+ update_output_window($static_output);
+ if (is_array($pkg_config['service']) && is_array($services)) {
+ foreach ($pkg_config['service'] as $service) {
+ foreach ($services as $key => $instservice) {
+ if ($instservice['name'] == $service['name']) {
+ if (platform_booting() != true) {
+ stop_service($service['name']);
+ }
+ if ($service['rcfile']) {
+ $prefix = RCFILEPREFIX;
+ if (!empty($service['prefix'])) {
+ $prefix = $service['prefix'];
+ }
+ if (file_exists("{$prefix}{$service['rcfile']}")) {
+ @unlink("{$prefix}{$service['rcfile']}");
+ }
+ }
+ unset($services[$key]);
+ }
+ }
+ }
+ }
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ }
+ /*
+ * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
+ * Same is done during installation.
+ */
+ write_config("Intermediate config write during package removal for {$package_name}.");
+
+ /*
+ * If a require exists, include it. this will
+ * show us where an error exists in a package
+ * instead of making us blindly guess
+ */
+ $missing_include = false;
+ if ($pkg_config['include_file'] <> "") {
+ $static_output .= gettext("Loading package instructions...") . "\n";
+ update_output_window($static_output);
+ if (file_exists($pkg_config['include_file'])) {
+ pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
+ require_once($pkg_config['include_file']);
+ } else {
+ pkg_debug("Missing include {$pkg_config['include_file']}\n");
+ $missing_include = true;
+ update_output_window($static_output);
+ $static_output .= "Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
+ }
+ }
+ /* ermal
+ * NOTE: It is not possible to handle parse errors on eval.
+ * So we prevent it from being run at all to not interrupt all the other code.
+ */
+ if ($when == "deinstall" && $missing_include == false) {
+ /* evaluate this package's global functions and pre deinstall commands */
+ if ($pkg_config['custom_php_global_functions'] <> "") {
+ eval_once($pkg_config['custom_php_global_functions']);
+ }
+ if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
+ eval_once($pkg_config['custom_php_pre_deinstall_command']);
+ }
+ }
+ /* deinstall commands */
+ if ($when == "post-deinstall" && $pkg_config['custom_php_deinstall_command'] <> "") {
+ $static_output .= gettext("Deinstall commands... ");
+ update_output_window($static_output);
+ if ($missing_include == false) {
+ eval_once($pkg_config['custom_php_deinstall_command']);
+ $static_output .= gettext("done.") . "\n";
+ } else {
+ $static_output .= "\nNot executing custom deinstall hook because an include is missing.\n";
+ }
+ update_output_window($static_output);
+ }
+ }
+ /* syslog */
+ if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfile_name'] <> "") {
+ $static_output .= "Syslog entries... ";
+ update_output_window($static_output);
+ remove_text_from_file("/etc/syslog.conf", $pkg_info['logging']['facilityname'] . "\t\t\t\t" . $pkg_info['logging']['logfilename']);
+ system_syslogd_start();
+ @unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
+ $static_output .= "done.\n";
+ update_output_window($static_output);
+ }
+
+ conf_mount_ro();
+ /* remove config.xml entries */
+ $static_output .= gettext("Configuration... ");
+ update_output_window($static_output);
+ unset($config['installedpackages']['package'][$pkgid]);
+ $static_output .= gettext("done.") . "\n";
+ update_output_window($static_output);
+ write_config("Removed {$package_name} package.\n");
+}
+
+function pkg_reinstall_all() {
+ global $g, $config;
+
+ // XXX: implement
+ return;
+}
+
+function stop_packages() {
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("filter.inc");
+ require_once("shaper.inc");
+ require_once("captiveportal.inc");
+ require_once("pkg-utils.inc");
+ require_once("pfsense-utils.inc");
+ require_once("service-utils.inc");
+
+ global $config, $g;
+
+ log_error("Stopping all packages.");
+
+ $rcfiles = glob(RCFILEPREFIX . "*.sh");
+ if (!$rcfiles) {
+ $rcfiles = array();
+ } else {
+ $rcfiles = array_flip($rcfiles);
+ if (!$rcfiles) {
+ $rcfiles = array();
+ }
+ }
+
+ if (is_array($config['installedpackages']['package'])) {
+ foreach ($config['installedpackages']['package'] as $package) {
+ echo " Stopping package {$package['name']}...";
+ $internal_name = get_package_internal_name($package);
+ stop_service($internal_name);
+ unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
+ echo "done.\n";
+ }
+ }
+
+ foreach ($rcfiles as $rcfile => $number) {
+ $shell = @popen("/bin/sh", "w");
+ if ($shell) {
+ echo " Stopping {$rcfile}...";
+ if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
+ if ($shell) {
+ pclose($shell);
+ }
+ $shell = @popen("/bin/sh", "w");
+ }
+ echo "done.\n";
+ pclose($shell);
+ }
+ }
+}
+
+function verify_all_package_servers() {
+ // XXX: Remove it after GUI is ready
+ return true;
+}
+
+function check_package_server_ssl() {
+ // XXX: Remove it after GUI is ready
+ return true;
+}
+
+?>
diff --git a/src/etc/inc/plain_sasl_client.inc b/src/etc/inc/plain_sasl_client.inc
new file mode 100644
index 0000000..691580c
--- /dev/null
+++ b/src/etc/inc/plain_sasl_client.inc
@@ -0,0 +1,99 @@
+<?php
+/*
+ * plain_sasl_client.php
+ *
+ * @(#) $Id: plain_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
+ *
+ */
+
+define("SASL_PLAIN_STATE_START", 0);
+define("SASL_PLAIN_STATE_IDENTIFY", 1);
+define("SASL_PLAIN_STATE_DONE", 2);
+
+define("SASL_PLAIN_DEFAULT_MODE", 0);
+define("SASL_PLAIN_EXIM_MODE", 1);
+define("SASL_PLAIN_EXIM_DOCUMENTATION_MODE", 2);
+
+class plain_sasl_client_class
+{
+ var $credentials=array();
+ var $state=SASL_PLAIN_STATE_START;
+
+ Function Initialize(&$client)
+ {
+ return(1);
+ }
+
+ Function Start(&$client, &$message, &$interactions)
+ {
+ if ($this->state!=SASL_PLAIN_STATE_START)
+ {
+ $client->error="PLAIN authentication state is not at the start";
+ return(SASL_FAIL);
+ }
+ $this->credentials=array(
+ "user"=>"",
+ "password"=>"",
+ "realm"=>"",
+ "mode"=>""
+ );
+ $defaults=array(
+ "realm"=>"",
+ "mode"=>""
+ );
+ $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
+ if ($status==SASL_CONTINUE)
+ {
+ switch ($this->credentials["mode"])
+ {
+ case SASL_PLAIN_EXIM_MODE:
+ $message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
+ break;
+ case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
+ $message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
+ break;
+ default:
+ $message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
+ break;
+ }
+ $this->state=SASL_PLAIN_STATE_DONE;
+ }
+ else
+ Unset($message);
+ return($status);
+ }
+
+ Function Step(&$client, $response, &$message, &$interactions)
+ {
+ switch ($this->state)
+ {
+/*
+ case SASL_PLAIN_STATE_IDENTIFY:
+ switch ($this->credentials["mode"])
+ {
+ case SASL_PLAIN_EXIM_MODE:
+ $message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
+ break;
+ case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
+ $message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
+ break;
+ default:
+ $message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
+ break;
+ }
+ var_dump($message);
+ $this->state=SASL_PLAIN_STATE_DONE;
+ break;
+*/
+ case SASL_PLAIN_STATE_DONE:
+ $client->error="PLAIN authentication was finished without success";
+ return(SASL_FAIL);
+ default:
+ $client->error="invalid PLAIN authentication step state";
+ return(SASL_FAIL);
+ }
+ return(SASL_CONTINUE);
+ }
+};
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/priv.defs.inc b/src/etc/inc/priv.defs.inc
new file mode 100644
index 0000000..7d2154f
--- /dev/null
+++ b/src/etc/inc/priv.defs.inc
@@ -0,0 +1,1403 @@
+<?php
+/*
+ * priv.defs.inc - Generated privilege definitions
+ *
+ */
+
+$priv_list = array();
+
+$priv_list['page-all'] = array();
+$priv_list['page-all']['name'] = gettext("WebCfg - All pages");
+$priv_list['page-all']['descr'] = gettext("Allow access to all pages");
+$priv_list['page-all']['match'] = array();
+$priv_list['page-all']['match'][] = "*";
+
+$priv_list['page-status-carp'] = array();
+$priv_list['page-status-carp']['name'] = gettext("WebCfg - Status: CARP page");
+$priv_list['page-status-carp']['descr'] = gettext("Allow access to the 'Status: CARP' page.");
+$priv_list['page-status-carp']['match'] = array();
+$priv_list['page-status-carp']['match'][] = "carp_status.php*";
+
+$priv_list['page-diagnostics-crash-reporter'] = array();
+$priv_list['page-diagnostics-crash-reporter']['name'] = gettext("WebCfg - Crash reporter");
+$priv_list['page-diagnostics-crash-reporter']['descr'] = gettext("Uploads crash reports to pfSense and or deletes crash reports.");
+$priv_list['page-diagnostics-crash-reporter']['match'] = array();
+$priv_list['page-diagnostics-crash-reporter']['match'][] = "crash_reporter.php*";
+
+$priv_list['page-diagnostics-arptable'] = array();
+$priv_list['page-diagnostics-arptable']['name'] = gettext("WebCfg - Diagnostics: ARP Table page");
+$priv_list['page-diagnostics-arptable']['descr'] = gettext("Allow access to the 'Diagnostics: ARP Table' page.");
+$priv_list['page-diagnostics-arptable']['match'] = array();
+$priv_list['page-diagnostics-arptable']['match'][] = "diag_arp.php*";
+
+$priv_list['page-diagnostics-authentication'] = array();
+$priv_list['page-diagnostics-authentication']['name'] = gettext("WebCfg - Diagnostics: Authentication page");
+$priv_list['page-diagnostics-authentication']['descr'] = gettext("Allow access to the 'Diagnostics: Authentication' page.");
+$priv_list['page-diagnostics-authentication']['match'] = array();
+$priv_list['page-diagnostics-authentication']['match'][] = "diag_authentication.php*";
+
+$priv_list['page-diagnostics-backup/restore'] = array();
+$priv_list['page-diagnostics-backup/restore']['name'] = gettext("WebCfg - Diagnostics: Backup/restore page");
+$priv_list['page-diagnostics-backup/restore']['descr'] = gettext("Allow access to the 'Diagnostics: Backup/restore' page.");
+$priv_list['page-diagnostics-backup/restore']['match'] = array();
+$priv_list['page-diagnostics-backup/restore']['match'][] = "diag_backup.php*";
+
+$priv_list['page-diagnostics-configurationhistory'] = array();
+$priv_list['page-diagnostics-configurationhistory']['name'] = gettext("WebCfg - Diagnostics: Configuration History page");
+$priv_list['page-diagnostics-configurationhistory']['descr'] = gettext("Allow access to the 'Diagnostics: Configuration History' page.");
+$priv_list['page-diagnostics-configurationhistory']['match'] = array();
+$priv_list['page-diagnostics-configurationhistory']['match'][] = "diag_confbak.php*";
+
+$priv_list['page-diagnostics-factorydefaults'] = array();
+$priv_list['page-diagnostics-factorydefaults']['name'] = gettext("WebCfg - Diagnostics: Factory defaults page");
+$priv_list['page-diagnostics-factorydefaults']['descr'] = gettext("Allow access to the 'Diagnostics: Factory defaults' page.");
+$priv_list['page-diagnostics-factorydefaults']['match'] = array();
+$priv_list['page-diagnostics-factorydefaults']['match'][] = "diag_defaults.php*";
+
+$priv_list['page-diagnostics-ndptable'] = array();
+$priv_list['page-diagnostics-ndptable']['name'] = gettext("Webcfg - Diagnostics: NDP Table page");
+$priv_list['page-diagnostics-ndptable']['descr'] = gettext("Allow access to the 'Diagnostics: NDP Table' page.");
+$priv_list['page-diagnostics-ndptable']['match'] = array();
+$priv_list['page-diagnostics-ndptable']['match'][] = "diag_ndp.php*";
+
+$priv_list['page-diagnostics-restore-full-backup'] = array();
+$priv_list['page-diagnostics-restore-full-backup']['name'] = gettext("Webcfg - Diagnostics: Restore full backup");
+$priv_list['page-diagnostics-restore-full-backup']['descr'] = gettext("Allow access to the 'Diagnostics: Restore Full Backup' page.");
+$priv_list['page-diagnostics-restore-full-backup']['match'] = array();
+$priv_list['page-diagnostics-restore-full-backup']['match'][] = "system_firmware_restorefullbackup.php";
+
+$priv_list['page-diagnostics-showstates'] = array();
+$priv_list['page-diagnostics-showstates']['name'] = gettext("WebCfg - Diagnostics: Show States page");
+$priv_list['page-diagnostics-showstates']['descr'] = gettext("Allow access to the 'Diagnostics: Show States' page.");
+$priv_list['page-diagnostics-showstates']['match'] = array();
+$priv_list['page-diagnostics-showstates']['match'][] = "diag_dump_states.php*";
+
+$priv_list['page-diagnostics-sockets'] = array();
+$priv_list['page-diagnostics-sockets']['name'] = gettext("WebCfg - Diagnostics: Sockets page");
+$priv_list['page-diagnostics-sockets']['descr'] = gettext("Allow access to the 'Diagnostics: Sockets' page.");
+$priv_list['page-diagnostics-sockets']['match'] = array();
+$priv_list['page-diagnostics-sockets']['match'][] = "diag_sockets.php*";
+
+$priv_list['page-diagnostics-testport'] = array();
+$priv_list['page-diagnostics-testport']['name'] = gettext("Webcfg - Diagnostics: Test Port");
+$priv_list['page-diagnostics-testport']['descr'] = gettext("Allow access to the 'Diagnostics: Test Port' page.");
+$priv_list['page-diagnostics-testport']['match'] = array();
+$priv_list['page-diagnostics-testport']['match'][] = "diag_testport.php*";
+
+$priv_list['page-status-ipsec'] = array();
+$priv_list['page-status-ipsec']['name'] = gettext("WebCfg - Status: IPsec page");
+$priv_list['page-status-ipsec']['descr'] = gettext("Allow access to the 'Status: IPsec' page.");
+$priv_list['page-status-ipsec']['match'] = array();
+$priv_list['page-status-ipsec']['match'][] = "diag_ipsec.php*";
+
+$priv_list['page-status-ipsec-leases'] = array();
+$priv_list['page-status-ipsec-leases']['name'] = gettext("WebCfg - Status: IPsec: Leasespage");
+$priv_list['page-status-ipsec-leases']['descr'] = gettext("Allow access to the 'Status: IPsec: Leases' page.");
+$priv_list['page-status-ipsec-leases']['match'] = array();
+$priv_list['page-status-ipsec-leases']['match'][] = "diag_ipsec_leases.php*";
+
+$priv_list['page-status-ipsec-sad'] = array();
+$priv_list['page-status-ipsec-sad']['name'] = gettext("WebCfg - Status: IPsec: SAD page");
+$priv_list['page-status-ipsec-sad']['descr'] = gettext("Allow access to the 'Status: IPsec: SAD' page.");
+$priv_list['page-status-ipsec-sad']['match'] = array();
+$priv_list['page-status-ipsec-sad']['match'][] = "diag_ipsec_sad.php*";
+
+$priv_list['page-status-ipsec-spd'] = array();
+$priv_list['page-status-ipsec-spd']['name'] = gettext("WebCfg - Status: IPsec: SPD page");
+$priv_list['page-status-ipsec-spd']['descr'] = gettext("Allow access to the 'Status: IPsec: SPD' page.");
+$priv_list['page-status-ipsec-spd']['match'] = array();
+$priv_list['page-status-ipsec-spd']['match'][] = "diag_ipsec_spd.php*";
+
+$priv_list['page-status-ntp'] = array();
+$priv_list['page-status-ntp']['name'] = gettext("Webcfg - Status: NTP page");
+$priv_list['page-status-ntp']['descr'] = gettext("Allow access to the 'Status: NTP' page.");
+$priv_list['page-status-ntp']['match'] = array();
+$priv_list['page-status-ntp']['match'][] = "status_ntpd.php*";
+
+$priv_list['page-ipsecxml'] = array();
+$priv_list['page-ipsecxml']['name'] = gettext("WebCfg - Diag IPsec XML page");
+$priv_list['page-ipsecxml']['descr'] = gettext("Allow access to the 'Diag IPsec XML' page.");
+$priv_list['page-ipsecxml']['match'] = array();
+$priv_list['page-ipsecxml']['match'][] = "diag_ipsec_xml.php";
+
+$priv_list['page-diagnostics-logs-system'] = array();
+$priv_list['page-diagnostics-logs-system']['name'] = gettext("WebCfg - Diagnostics: Logs: System page");
+$priv_list['page-diagnostics-logs-system']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: System' page.");
+$priv_list['page-diagnostics-logs-system']['match'] = array();
+$priv_list['page-diagnostics-logs-system']['match'][] = "diag_logs.php*";
+
+$priv_list['page-status-systemlogs-portalauth'] = array();
+$priv_list['page-status-systemlogs-portalauth']['name'] = gettext("WebCfg - Status: System logs: Portal Auth page");
+$priv_list['page-status-systemlogs-portalauth']['descr'] = gettext("Allow access to the 'Status: System logs: Portal Auth' page.");
+$priv_list['page-status-systemlogs-portalauth']['match'] = array();
+$priv_list['page-status-systemlogs-portalauth']['match'][] = "diag_logs_auth.php*";
+
+$priv_list['page-diagnostics-logs-dhcp'] = array();
+$priv_list['page-diagnostics-logs-dhcp']['name'] = gettext("WebCfg - Diagnostics: Logs: DHCP page");
+$priv_list['page-diagnostics-logs-dhcp']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: DHCP' page.");
+$priv_list['page-diagnostics-logs-dhcp']['match'] = array();
+$priv_list['page-diagnostics-logs-dhcp']['match'][] = "diag_logs_dhcp.php*";
+
+$priv_list['page-diagnostics-logs-firewall'] = array();
+$priv_list['page-diagnostics-logs-firewall']['name'] = gettext("WebCfg - Diagnostics: Logs: Firewall page");
+$priv_list['page-diagnostics-logs-firewall']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: Firewall' page.");
+$priv_list['page-diagnostics-logs-firewall']['match'] = array();
+$priv_list['page-diagnostics-logs-firewall']['match'][] = "diag_logs_filter.php*";
+
+$priv_list['page-diagnostics-logs-gateways'] = array();
+$priv_list['page-diagnostics-logs-gateways']['name'] = gettext("WebCfg - Diagnostics: Logs: Gateways page");
+$priv_list['page-diagnostics-logs-gateways']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: System: Gateways' page.");
+$priv_list['page-diagnostics-logs-gateways']['match'] = array();
+$priv_list['page-diagnostics-logs-gateways']['match'][] = "diag_logs_gateways.php*";
+
+$priv_list['page-diagnostics-logs-resolver'] = array();
+$priv_list['page-diagnostics-logs-resolver']['name'] = gettext("WebCfg - Diagnostics: Logs: Resolver page");
+$priv_list['page-diagnostics-logs-resolver']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: System: Resolver' page.");
+$priv_list['page-diagnostics-logs-resolver']['match'] = array();
+$priv_list['page-diagnostics-logs-resolver']['match'][] = "diag_logs_resolver.php*";
+
+$priv_list['page-hidden-nolongerincluded'] = array();
+$priv_list['page-hidden-nolongerincluded']['name'] = gettext("WebCfg - Hidden: No longer included page");
+$priv_list['page-hidden-nolongerincluded']['descr'] = gettext("Allow access to the 'Hidden: No longer included' page.");
+$priv_list['page-hidden-nolongerincluded']['match'] = array();
+$priv_list['page-hidden-nolongerincluded']['match'][] = "diag_logs_filter_dynamic.php*";
+
+$priv_list['page-status-systemlogs-ipsecvpn'] = array();
+$priv_list['page-status-systemlogs-ipsecvpn']['name'] = gettext("WebCfg - Status: System logs: IPsec VPN page");
+$priv_list['page-status-systemlogs-ipsecvpn']['descr'] = gettext("Allow access to the 'Status: System logs: IPsec VPN' page.");
+$priv_list['page-status-systemlogs-ipsecvpn']['match'] = array();
+$priv_list['page-status-systemlogs-ipsecvpn']['match'][] = "diag_logs_ipsec.php*";
+
+$priv_list['page-status-systemlogs-ntpd'] = array();
+$priv_list['page-status-systemlogs-ntpd']['name'] = gettext("WebCfg - Status: System logs: NTP page");
+$priv_list['page-status-systemlogs-ntpd']['descr'] = gettext("Allow access to the 'Status: System logs: NTP' page.");
+$priv_list['page-status-systemlogs-ntpd']['match'] = array();
+$priv_list['page-status-systemlogs-ntpd']['match'][] = "diag_logs_ntpd.php*";
+
+$priv_list['page-status-systemlogs-openvpn'] = array();
+$priv_list['page-status-systemlogs-openvpn']['name'] = gettext("WebCfg - Status: System logs: OpenVPN page");
+$priv_list['page-status-systemlogs-openvpn']['descr'] = gettext("Allow access to the 'Status: System logs: OpenVPN' page.");
+$priv_list['page-status-systemlogs-openvpn']['match'] = array();
+$priv_list['page-status-systemlogs-openvpn']['match'][] = "diag_logs_openvpn.php*";
+
+$priv_list['page-status-systemlogs-ppp'] = array();
+$priv_list['page-status-systemlogs-ppp']['name'] = gettext("WebCfg - Status: System logs: IPsec VPN page");
+$priv_list['page-status-systemlogs-ppp']['descr'] = gettext("Allow access to the 'Status: System logs: IPsec VPN' page.");
+$priv_list['page-status-systemlogs-ppp']['match'] = array();
+$priv_list['page-status-systemlogs-ppp']['match'][] = "diag_logs_ppp.php*";
+
+$priv_list['page-status-systemlogs-loadbalancer'] = array();
+$priv_list['page-status-systemlogs-loadbalancer']['name'] = gettext("WebCfg - Status: System logs: Load Balancer page");
+$priv_list['page-status-systemlogs-loadbalancer']['descr'] = gettext("Allow access to the 'Status: System logs: Load Balancer' page.");
+$priv_list['page-status-systemlogs-loadbalancer']['match'] = array();
+$priv_list['page-status-systemlogs-loadbalancer']['match'][] = "diag_logs_relayd.php*";
+
+$priv_list['page-status-systemlogs-routing'] = array();
+$priv_list['page-status-systemlogs-routing']['name'] = gettext("Webcfg - Status: System logs: Routing page");
+$priv_list['page-status-systemlogs-routing']['descr'] = gettext("Allow access to the 'Status: System logs: System: Routing' page.");
+$priv_list['page-status-systemlogs-routing']['match'] = array();
+$priv_list['page-status-systemlogs-routing']['match'][] = "diag_logs_routing.php*";
+
+$priv_list['page-status-systemlogs-wireless'] = array();
+$priv_list['page-status-systemlogs-wireless']['name'] = gettext("Webcfg - Status: System logs: Wireless page");
+$priv_list['page-status-systemlogs-wireless']['descr'] = gettext("Allow access to the 'Status: System logs: System: Wireless' page.");
+$priv_list['page-status-systemlogs-wireless']['match'] = array();
+$priv_list['page-status-systemlogs-wireless']['match'][] = "diag_logs_wireless.php*";
+
+$priv_list['page-diagnostics-logs-settings'] = array();
+$priv_list['page-diagnostics-logs-settings']['name'] = gettext("WebCfg - Diagnostics: Logs: Settings page");
+$priv_list['page-diagnostics-logs-settings']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: Settings' page.");
+$priv_list['page-diagnostics-logs-settings']['match'] = array();
+$priv_list['page-diagnostics-logs-settings']['match'][] = "diag_logs_settings.php*";
+
+$priv_list['page-diagnostics-logs-pptpvpn'] = array();
+$priv_list['page-diagnostics-logs-pptpvpn']['name'] = gettext("WebCfg - Diagnostics: Logs: VPN page");
+$priv_list['page-diagnostics-logs-pptpvpn']['descr'] = gettext("Allow access to the 'Diagnostics: Logs: VPN' page.");
+$priv_list['page-diagnostics-logs-pptpvpn']['match'] = array();
+$priv_list['page-diagnostics-logs-pptpvpn']['match'][] = "diag_logs_vpn.php*";
+
+$priv_list['page-diagnostics-nanobsd'] = array();
+$priv_list['page-diagnostics-nanobsd']['name'] = gettext("WebCfg - Diagnostics: NanoBSD");
+$priv_list['page-diagnostics-nanobsd']['descr'] = gettext("Allow access to the 'Diagnostics: NanoBSD' page.");
+$priv_list['page-diagnostics-nanobsd']['match'] = array();
+$priv_list['page-diagnostics-nanobsd']['match'][] = "diag_nanobsd.php*";
+
+$priv_list['page-diagnostics-packetcapture'] = array();
+$priv_list['page-diagnostics-packetcapture']['name'] = gettext("WebCfg - Diagnostics: Packet Capture page");
+$priv_list['page-diagnostics-packetcapture']['descr'] = gettext("Allow access to the 'Diagnostics: Packet Capture' page.");
+$priv_list['page-diagnostics-packetcapture']['match'] = array();
+$priv_list['page-diagnostics-packetcapture']['match'][] = "diag_packet_capture.php*";
+
+$priv_list['page-diagnostics-patters'] = array();
+$priv_list['page-diagnostics-patters']['name'] = gettext("WebCfg - Diagnostics: Patterns page");
+$priv_list['page-diagnostics-patters']['descr'] = gettext("Allow access to the 'Diagnostics: Patterns' page.");
+$priv_list['page-diagnostics-patters']['match'] = array();
+$priv_list['page-diagnostics-patters']['match'][] = "patterns.php*";
+
+$priv_list['page-diagnostics-limiter-info'] = array();
+$priv_list['page-diagnostics-limiter-info']['name'] = gettext("Diagnostics: Limiter Info");
+$priv_list['page-diagnostics-limiter-info']['descr'] = gettext("Allows access to the 'Diagnostics: Limiter Info' page");
+$priv_list['page-diagnostics-limiter-info']['match'] = array();
+$priv_list['page-diagnostics-limiter-info']['match'][] = "diag_limiter_info.php*";
+
+$priv_list['page-diagnostics-pf-info'] = array();
+$priv_list['page-diagnostics-pf-info']['name'] = gettext("Diagnostics: pfInfo");
+$priv_list['page-diagnostics-pf-info']['descr'] = gettext("Allows access to the 'Diagnostics: pfInfo' page");
+$priv_list['page-diagnostics-pf-info']['match'] = array();
+$priv_list['page-diagnostics-pf-info']['match'][] = "diag_pf_info.php*";
+
+$priv_list['page-diagnostics-system-activity'] = array();
+$priv_list['page-diagnostics-system-activity']['name'] = gettext("WebCfg - Diagnostics: System Activity");
+$priv_list['page-diagnostics-system-activity']['descr'] = gettext("Allows access to the 'Diagnostics: System Activity' page");
+$priv_list['page-diagnostics-system-activity']['match'] = array();
+$priv_list['page-diagnostics-system-activity']['match'][] = "diag_system_activity.php*";
+
+$priv_list['page-diagnostics-system-pftop'] = array();
+$priv_list['page-diagnostics-system-pftop']['name'] = gettext("Diagnostics: pfTop");
+$priv_list['page-diagnostics-system-pftop']['descr'] = gettext("Allows access to the 'Diagnostics: pfTop' page");
+$priv_list['page-diagnostics-system-pftop']['match'] = array();
+$priv_list['page-diagnostics-system-pftop']['match'][] = "diag_system_pftop.php*";
+
+$priv_list['page-diagnostics-ping'] = array();
+$priv_list['page-diagnostics-ping']['name'] = gettext("WebCfg - Diagnostics: Ping page");
+$priv_list['page-diagnostics-ping']['descr'] = gettext("Allow access to the 'Diagnostics: Ping' page.");
+$priv_list['page-diagnostics-ping']['match'] = array();
+$priv_list['page-diagnostics-ping']['match'][] = "diag_ping.php*";
+
+$priv_list['page-status-packagelogs'] = array();
+$priv_list['page-status-packagelogs']['name'] = gettext("WebCfg - Status: Package logs page");
+$priv_list['page-status-packagelogs']['descr'] = gettext("Allow access to the 'Status: Package logs' page.");
+$priv_list['page-status-packagelogs']['match'] = array();
+$priv_list['page-status-packagelogs']['match'][] = "diag_pkglogs.php*";
+
+$priv_list['page-diagnostics-resetstate'] = array();
+$priv_list['page-diagnostics-resetstate']['name'] = gettext("WebCfg - Diagnostics: Reset state page");
+$priv_list['page-diagnostics-resetstate']['descr'] = gettext("Allow access to the 'Diagnostics: Reset state' page.");
+$priv_list['page-diagnostics-resetstate']['match'] = array();
+$priv_list['page-diagnostics-resetstate']['match'][] = "diag_resetstate.php*";
+
+$priv_list['page-diagnostics-routingtables'] = array();
+$priv_list['page-diagnostics-routingtables']['name'] = gettext("WebCfg - Diagnostics: Routing tables page");
+$priv_list['page-diagnostics-routingtables']['descr'] = gettext("Allow access to the 'Diagnostics: Routing tables' page.");
+$priv_list['page-diagnostics-routingtables']['match'] = array();
+$priv_list['page-diagnostics-routingtables']['match'][] = "diag_routes.php*";
+
+$priv_list['page-diagnostics-statessummary'] = array();
+$priv_list['page-diagnostics-statessummary']['name'] = gettext("WebCfg - Diagnostics: States Summary page");
+$priv_list['page-diagnostics-statessummary']['descr'] = gettext("Allow access to the 'Diagnostics: States Summary' page.");
+$priv_list['page-diagnostics-statessummary']['match'] = array();
+$priv_list['page-diagnostics-statessummary']['match'][] = "diag_states_summary.php*";
+
+$priv_list['page-diagnostics-tables'] = array();
+$priv_list['page-diagnostics-tables']['name'] = gettext("WebCfg - Diagnostics: PF Table IP addresses");
+$priv_list['page-diagnostics-tables']['descr'] = gettext("Allow access to the 'Diagnostics: Tables' page.");
+$priv_list['page-diagnostics-tables']['match'] = array();
+$priv_list['page-diagnostics-tables']['match'][] = "diag_tables.php*";
+
+$priv_list['page-diagnostics-traceroute'] = array();
+$priv_list['page-diagnostics-traceroute']['name'] = gettext("WebCfg - Diagnostics: Traceroute page");
+$priv_list['page-diagnostics-traceroute']['descr'] = gettext("Allow access to the 'Diagnostics: Traceroute' page.");
+$priv_list['page-diagnostics-traceroute']['match'] = array();
+$priv_list['page-diagnostics-traceroute']['match'][] = "diag_traceroute.php*";
+
+$priv_list['page-diagnostics-edit'] = array();
+$priv_list['page-diagnostics-edit']['name'] = gettext("WebCfg - Diagnostics: Edit FIle");
+$priv_list['page-diagnostics-edit']['descr'] = gettext("Allow access to the 'Diagnostics: Edit File' page.");
+$priv_list['page-diagnostics-edit']['match'] = array();
+$priv_list['page-diagnostics-edit']['match'][] = "edit.php*";
+$priv_list['page-diagnostics-edit']['match'][] = "browser.php*";
+$priv_list['page-diagnostics-edit']['match'][] = "filebrowser/browser.php*";
+
+$priv_list['page-diagnostics-command'] = array();
+$priv_list['page-diagnostics-command']['name'] = gettext("WebCfg - Diagnostics: Command page");
+$priv_list['page-diagnostics-command']['descr'] = gettext("Allow access to the 'Diagnostics: Command' page.");
+$priv_list['page-diagnostics-command']['match'] = array();
+$priv_list['page-diagnostics-command']['match'][] = "exec.php*";
+
+$priv_list['page-firewall-aliases'] = array();
+$priv_list['page-firewall-aliases']['name'] = gettext("WebCfg - Firewall: Aliases page");
+$priv_list['page-firewall-aliases']['descr'] = gettext("Allow access to the 'Firewall: Aliases' page.");
+$priv_list['page-firewall-aliases']['match'] = array();
+$priv_list['page-firewall-aliases']['match'][] = "firewall_aliases.php*";
+
+$priv_list['page-firewall-alias-edit'] = array();
+$priv_list['page-firewall-alias-edit']['name'] = gettext("WebCfg - Firewall: Alias: Edit page");
+$priv_list['page-firewall-alias-edit']['descr'] = gettext("Allow access to the 'Firewall: Alias: Edit' page.");
+$priv_list['page-firewall-alias-edit']['match'] = array();
+$priv_list['page-firewall-alias-edit']['match'][] = "firewall_aliases_edit.php*";
+
+$priv_list['page-firewall-alias-import'] = array();
+$priv_list['page-firewall-alias-import']['name'] = gettext("WebCfg - Firewall: Alias: Import page");
+$priv_list['page-firewall-alias-import']['descr'] = gettext("Allow access to the 'Firewall: Alias: Import' page.");
+$priv_list['page-firewall-alias-import']['match'] = array();
+$priv_list['page-firewall-alias-import']['match'][] = "firewall_aliases_import.php*";
+
+$priv_list['page-firewall-nat-npt'] = array();
+$priv_list['page-firewall-nat-npt']['name'] = gettext("Webcfg - Firewall: NAT: NPT page");
+$priv_list['page-firewall-nat-npt']['descr'] = gettext("Allow access to the 'Firewall: NAT: NPT' page.");
+$priv_list['page-firewall-nat-npt']['match'] = array();
+$priv_list['page-firewall-nat-npt']['match'][] = "firewall_nat_npt.php*";
+
+$priv_list['page-firewall-nat-npt-edit'] = array();
+$priv_list['page-firewall-nat-npt-edit']['name'] = gettext("Webcfg - Firewall: NAT: NPt: Edit page");
+$priv_list['page-firewall-nat-npt-edit']['descr'] = gettext("Allow access to the 'Firewall: NAT: NPt: Edit' page.");
+$priv_list['page-firewall-nat-npt-edit']['match'] = array();
+$priv_list['page-firewall-nat-npt-edit']['match'][] = "firewall_nat_npt_edit.php*";
+
+$priv_list['page-firewall-nat-portforward'] = array();
+$priv_list['page-firewall-nat-portforward']['name'] = gettext("WebCfg - Firewall: NAT: Port Forward page");
+$priv_list['page-firewall-nat-portforward']['descr'] = gettext("Allow access to the 'Firewall: NAT: Port Forward' page.");
+$priv_list['page-firewall-nat-portforward']['match'] = array();
+$priv_list['page-firewall-nat-portforward']['match'][] = "firewall_nat.php*";
+
+$priv_list['page-firewall-nat-1-1'] = array();
+$priv_list['page-firewall-nat-1-1']['name'] = gettext("WebCfg - Firewall: NAT: 1:1 page");
+$priv_list['page-firewall-nat-1-1']['descr'] = gettext("Allow access to the 'Firewall: NAT: 1:1' page.");
+$priv_list['page-firewall-nat-1-1']['match'] = array();
+$priv_list['page-firewall-nat-1-1']['match'][] = "firewall_nat_1to1.php*";
+
+$priv_list['page-firewall-nat-1-1-edit'] = array();
+$priv_list['page-firewall-nat-1-1-edit']['name'] = gettext("WebCfg - Firewall: NAT: 1:1: Edit page");
+$priv_list['page-firewall-nat-1-1-edit']['descr'] = gettext("Allow access to the 'Firewall: NAT: 1:1: Edit' page.");
+$priv_list['page-firewall-nat-1-1-edit']['match'] = array();
+$priv_list['page-firewall-nat-1-1-edit']['match'][] = "firewall_nat_1to1_edit.php*";
+
+$priv_list['page-firewall-nat-portforward-edit'] = array();
+$priv_list['page-firewall-nat-portforward-edit']['name'] = gettext("WebCfg - Firewall: NAT: Port Forward: Edit page");
+$priv_list['page-firewall-nat-portforward-edit']['descr'] = gettext("Allow access to the 'Firewall: NAT: Port Forward: Edit' page.");
+$priv_list['page-firewall-nat-portforward-edit']['match'] = array();
+$priv_list['page-firewall-nat-portforward-edit']['match'][] = "firewall_nat_edit.php*";
+
+$priv_list['page-firewall-nat-outbound'] = array();
+$priv_list['page-firewall-nat-outbound']['name'] = gettext("WebCfg - Firewall: NAT: Outbound page");
+$priv_list['page-firewall-nat-outbound']['descr'] = gettext("Allow access to the 'Firewall: NAT: Outbound' page.");
+$priv_list['page-firewall-nat-outbound']['match'] = array();
+$priv_list['page-firewall-nat-outbound']['match'][] = "firewall_nat_out.php*";
+
+$priv_list['page-firewall-nat-outbound-edit'] = array();
+$priv_list['page-firewall-nat-outbound-edit']['name'] = gettext("WebCfg - Firewall: NAT: Outbound: Edit page");
+$priv_list['page-firewall-nat-outbound-edit']['descr'] = gettext("Allow access to the 'Firewall: NAT: Outbound: Edit' page.");
+$priv_list['page-firewall-nat-outbound-edit']['match'] = array();
+$priv_list['page-firewall-nat-outbound-edit']['match'][] = "firewall_nat_out_edit.php*";
+
+$priv_list['page-firewall-rules'] = array();
+$priv_list['page-firewall-rules']['name'] = gettext("WebCfg - Firewall: Rules page");
+$priv_list['page-firewall-rules']['descr'] = gettext("Allow access to the 'Firewall: Rules' page.");
+$priv_list['page-firewall-rules']['match'] = array();
+$priv_list['page-firewall-rules']['match'][] = "firewall_rules.php*";
+
+$priv_list['page-firewall-rules-edit'] = array();
+$priv_list['page-firewall-rules-edit']['name'] = gettext("WebCfg - Firewall: Rules: Edit page");
+$priv_list['page-firewall-rules-edit']['descr'] = gettext("Allow access to the 'Firewall: Rules: Edit' page.");
+$priv_list['page-firewall-rules-edit']['match'] = array();
+$priv_list['page-firewall-rules-edit']['match'][] = "firewall_rules_edit.php*";
+
+$priv_list['page-firewall-schedules'] = array();
+$priv_list['page-firewall-schedules']['name'] = gettext("WebCfg - Firewall: Schedules page");
+$priv_list['page-firewall-schedules']['descr'] = gettext("Allow access to the 'Firewall: Schedules' page.");
+$priv_list['page-firewall-schedules']['match'] = array();
+$priv_list['page-firewall-schedules']['match'][] = "firewall_schedule.php*";
+
+$priv_list['page-firewall-schedules-edit'] = array();
+$priv_list['page-firewall-schedules-edit']['name'] = gettext("WebCfg - Firewall: Schedules: Edit page");
+$priv_list['page-firewall-schedules-edit']['descr'] = gettext("Allow access to the 'Firewall: Schedules: Edit' page.");
+$priv_list['page-firewall-schedules-edit']['match'] = array();
+$priv_list['page-firewall-schedules-edit']['match'][] = "firewall_schedule_edit.php*";
+
+$priv_list['page-firewall-trafficshaper'] = array();
+$priv_list['page-firewall-trafficshaper']['name'] = gettext("WebCfg - Firewall: Traffic Shaper page");
+$priv_list['page-firewall-trafficshaper']['descr'] = gettext("Allow access to the 'Firewall: Traffic Shaper' page.");
+$priv_list['page-firewall-trafficshaper']['match'] = array();
+$priv_list['page-firewall-trafficshaper']['match'][] = "firewall_shaper.php*";
+
+$priv_list['page-firewall-trafficshaper-layer7'] = array();
+$priv_list['page-firewall-trafficshaper-layer7']['name'] = gettext("WebCfg - Firewall: Traffic Shaper: Layer7 page");
+$priv_list['page-firewall-trafficshaper-layer7']['descr'] = gettext("Allow access to the 'Firewall: Traffic Shaper: Layer7' page.");
+$priv_list['page-firewall-trafficshaper-layer7']['match'] = array();
+$priv_list['page-firewall-trafficshaper-layer7']['match'][] = "firewall_shaper_layer7.php*";
+
+$priv_list['page-firewall-trafficshaper-queues'] = array();
+$priv_list['page-firewall-trafficshaper-queues']['name'] = gettext("WebCfg - Firewall: Traffic Shaper: Queues page");
+$priv_list['page-firewall-trafficshaper-queues']['descr'] = gettext("Allow access to the 'Firewall: Traffic Shaper: Queues' page.");
+$priv_list['page-firewall-trafficshaper-queues']['match'] = array();
+$priv_list['page-firewall-trafficshaper-queues']['match'][] = "firewall_shaper_queues.php*";
+
+$priv_list['page-firewall-trafficshaper-limiter'] = array();
+$priv_list['page-firewall-trafficshaper-limiter']['name'] = gettext("WebCfg - Firewall: Traffic Shaper: Limiter page");
+$priv_list['page-firewall-trafficshaper-limiter']['descr'] = gettext("Allow access to the 'Firewall: Traffic Shaper: Limiter' page.");
+$priv_list['page-firewall-trafficshaper-limiter']['match'] = array();
+$priv_list['page-firewall-trafficshaper-limiter']['match'][] = "firewall_shaper_vinterface.php*";
+
+$priv_list['page-firewall-trafficshaper-wizard'] = array();
+$priv_list['page-firewall-trafficshaper-wizard']['name'] = gettext("WebCfg - Firewall: Traffic Shaper: Wizard page");
+$priv_list['page-firewall-trafficshaper-wizard']['descr'] = gettext("Allow access to the 'Firewall: Traffic Shaper: Wizard' page.");
+$priv_list['page-firewall-trafficshaper-wizard']['match'] = array();
+$priv_list['page-firewall-trafficshaper-wizard']['match'][] = "firewall_shaper_wizards.php*";
+
+$priv_list['page-firewall-virtualipaddresses'] = array();
+$priv_list['page-firewall-virtualipaddresses']['name'] = gettext("WebCfg - Firewall: Virtual IP Addresses page");
+$priv_list['page-firewall-virtualipaddresses']['descr'] = gettext("Allow access to the 'Firewall: Virtual IP Addresses' page.");
+$priv_list['page-firewall-virtualipaddresses']['match'] = array();
+$priv_list['page-firewall-virtualipaddresses']['match'][] = "firewall_virtual_ip.php*";
+
+$priv_list['page-firewall-virtualipaddress-edit'] = array();
+$priv_list['page-firewall-virtualipaddress-edit']['name'] = gettext("WebCfg - Firewall: Virtual IP Address: Edit page");
+$priv_list['page-firewall-virtualipaddress-edit']['descr'] = gettext("Allow access to the 'Firewall: Virtual IP Address: Edit' page.");
+$priv_list['page-firewall-virtualipaddress-edit']['match'] = array();
+$priv_list['page-firewall-virtualipaddress-edit']['match'][] = "firewall_virtual_ip_edit.php*";
+
+$priv_list['page-getserviceproviders'] = array();
+$priv_list['page-getserviceproviders']['name'] = gettext("WebCfg - AJAX: Get Service Providers");
+$priv_list['page-getserviceproviders']['descr'] = gettext("Allow access to the 'AJAX: Service Providers' page.");
+$priv_list['page-getserviceproviders']['match'] = array();
+$priv_list['page-getserviceproviders']['match'][] = "getserviceproviders.php*";
+
+$priv_list['page-getstats'] = array();
+$priv_list['page-getstats']['name'] = gettext("WebCfg - AJAX: Get Stats");
+$priv_list['page-getstats']['descr'] = gettext("Allow access to the 'AJAX: Get Stats' page.");
+$priv_list['page-getstats']['match'] = array();
+$priv_list['page-getstats']['match'][] = "getstats.php*";
+
+$priv_list['page-diagnostics-interfacetraffic'] = array();
+$priv_list['page-diagnostics-interfacetraffic']['name'] = gettext("WebCfg - Diagnostics: Interface Traffic page");
+$priv_list['page-diagnostics-interfacetraffic']['descr'] = gettext("Allow access to the 'Diagnostics: Interface Traffic' page.");
+$priv_list['page-diagnostics-interfacetraffic']['match'] = array();
+$priv_list['page-diagnostics-interfacetraffic']['match'][] = "graph.php*";
+
+$priv_list['page-diagnostics-cpuutilization'] = array();
+$priv_list['page-diagnostics-cpuutilization']['name'] = gettext("WebCfg - Diagnostics: CPU Utilization page");
+$priv_list['page-diagnostics-cpuutilization']['descr'] = gettext("Allow access to the 'Diagnostics: CPU Utilization' page.");
+$priv_list['page-diagnostics-cpuutilization']['match'] = array();
+$priv_list['page-diagnostics-cpuutilization']['match'][] = "graph_cpu.php*";
+
+$priv_list['page-diagnostics-haltsystem'] = array();
+$priv_list['page-diagnostics-haltsystem']['name'] = gettext("WebCfg - Diagnostics: Halt system page");
+$priv_list['page-diagnostics-haltsystem']['descr'] = gettext("Allow access to the 'Diagnostics: Halt system' page.");
+$priv_list['page-diagnostics-haltsystem']['match'] = array();
+$priv_list['page-diagnostics-haltsystem']['match'][] = "halt.php*";
+
+$priv_list['page-requiredforjavascript'] = array();
+$priv_list['page-requiredforjavascript']['name'] = gettext("WebCfg - Required for javascript page");
+$priv_list['page-requiredforjavascript']['descr'] = gettext("Allow access to the 'Required for javascript' page.");
+$priv_list['page-requiredforjavascript']['match'] = array();
+$priv_list['page-requiredforjavascript']['match'][] = "headjs.php*";
+
+$priv_list['page-xmlrpcinterfacestats'] = array();
+$priv_list['page-xmlrpcinterfacestats']['name'] = gettext("WebCfg - XMLRPC Interface Stats page");
+$priv_list['page-xmlrpcinterfacestats']['descr'] = gettext("Allow access to the 'XMLRPC Interface Stats' page.");
+$priv_list['page-xmlrpcinterfacestats']['match'] = array();
+$priv_list['page-xmlrpcinterfacestats']['match'][] = "ifstats.php*";
+
+$priv_list['page-system-login/logout'] = array();
+$priv_list['page-system-login/logout']['name'] = gettext("WebCfg - System: Login / Logout page / Dashboard");
+$priv_list['page-system-login/logout']['descr'] = gettext("Allow access to the 'System: Login / Logout' page and Dashboard.");
+$priv_list['page-system-login/logout']['match'] = array();
+$priv_list['page-system-login/logout']['match'][] = "index.php*";
+
+$priv_list['page-interfaces'] = array();
+$priv_list['page-interfaces']['name'] = gettext("WebCfg - Interfaces: WAN page");
+$priv_list['page-interfaces']['descr'] = gettext("Allow access to the 'Interfaces' page.");
+$priv_list['page-interfaces']['match'] = array();
+$priv_list['page-interfaces']['match'][] = "interfaces.php*";
+
+$priv_list['page-interfaces-assignnetworkports'] = array();
+$priv_list['page-interfaces-assignnetworkports']['name'] = gettext("WebCfg - Interfaces: Assign network ports page");
+$priv_list['page-interfaces-assignnetworkports']['descr'] = gettext("Allow access to the 'Interfaces: Assign network ports' page.");
+$priv_list['page-interfaces-assignnetworkports']['match'] = array();
+$priv_list['page-interfaces-assignnetworkports']['match'][] = "interfaces_assign.php*";
+
+$priv_list['page-interfaces-bridge'] = array();
+$priv_list['page-interfaces-bridge']['name'] = gettext("WebCfg - Interfaces: Bridge page");
+$priv_list['page-interfaces-bridge']['descr'] = gettext("Allow access to the 'Interfaces: Bridge' page.");
+$priv_list['page-interfaces-bridge']['match'] = array();
+$priv_list['page-interfaces-bridge']['match'][] = "interfaces_bridge.php*";
+
+$priv_list['page-interfaces-bridge-edit'] = array();
+$priv_list['page-interfaces-bridge-edit']['name'] = gettext("WebCfg - Interfaces: Bridge edit page");
+$priv_list['page-interfaces-bridge-edit']['descr'] = gettext("Allow access to the 'Interfaces: Bridge : Edit' page.");
+$priv_list['page-interfaces-bridge-edit']['match'] = array();
+$priv_list['page-interfaces-bridge-edit']['match'][] = "interfaces_bridge_edit.php*";
+
+$priv_list['page-interfaces-gif'] = array();
+$priv_list['page-interfaces-gif']['name'] = gettext("WebCfg - Interfaces: GIF page");
+$priv_list['page-interfaces-gif']['descr'] = gettext("Allow access to the 'Interfaces: GIF' page.");
+$priv_list['page-interfaces-gif']['match'] = array();
+$priv_list['page-interfaces-gif']['match'][] = "interfaces_gif.php*";
+
+$priv_list['page-interfaces-gif-edit'] = array();
+$priv_list['page-interfaces-gif-edit']['name'] = gettext("WebCfg - Interfaces: GIF: Edit page");
+$priv_list['page-interfaces-gif-edit']['descr'] = gettext("Allow access to the 'Interfaces: GIF: Edit' page.");
+$priv_list['page-interfaces-gif-edit']['match'] = array();
+$priv_list['page-interfaces-gif-edit']['match'][] = "interfaces_gif_edit.php*";
+
+$priv_list['page-interfaces-gre'] = array();
+$priv_list['page-interfaces-gre']['name'] = gettext("WebCfg - Interfaces: GRE page");
+$priv_list['page-interfaces-gre']['descr'] = gettext("Allow access to the 'Interfaces: GRE' page.");
+$priv_list['page-interfaces-gre']['match'] = array();
+$priv_list['page-interfaces-gre']['match'][] = "interfaces_gre.php*";
+
+$priv_list['page-interfaces-gre-edit'] = array();
+$priv_list['page-interfaces-gre-edit']['name'] = gettext("WebCfg - Interfaces: GRE: Edit page");
+$priv_list['page-interfaces-gre-edit']['descr'] = gettext("Allow access to the 'Interfaces: GRE: Edit' page.");
+$priv_list['page-interfaces-gre-edit']['match'] = array();
+$priv_list['page-interfaces-gre-edit']['match'][] = "interfaces_gre_edit.php*";
+
+$priv_list['page-interfaces-groups'] = array();
+$priv_list['page-interfaces-groups']['name'] = gettext("WebCfg - Interfaces: Groups page");
+$priv_list['page-interfaces-groups']['descr'] = gettext("Create interface groups");
+$priv_list['page-interfaces-groups']['match'] = array();
+$priv_list['page-interfaces-groups']['match'][] = "interfaces_groups.php*";
+
+$priv_list['page-interfaces-groups-edit'] = array();
+$priv_list['page-interfaces-groups-edit']['name'] = gettext("Interfaces: Groups: Edit page");
+$priv_list['page-interfaces-groups-edit']['descr'] = gettext("Allow access to the 'Interfaces: Groups: Edit' page.");
+$priv_list['page-interfaces-groups-edit']['match'] = array();
+$priv_list['page-interfaces-groups-edit']['match'][] = "interfaces_groups_edit.php*";
+
+$priv_list['page-interfaces-lagg'] = array();
+$priv_list['page-interfaces-lagg']['name'] = gettext("WebCfg - Interfaces: LAGG: page");
+$priv_list['page-interfaces-lagg']['descr'] = gettext("Edit Interface LAGG");
+$priv_list['page-interfaces-lagg']['match'] = array();
+$priv_list['page-interfaces-lagg']['match'][] = "interfaces_lagg.php*";
+
+$priv_list['page-interfaces-lagg-edit'] = array();
+$priv_list['page-interfaces-lagg-edit']['name'] = gettext("Interfaces: LAGG: Edit page");
+$priv_list['page-interfaces-lagg-edit']['descr'] = gettext("Allow access to the 'Interfaces: LAGG: Edit' page.");
+$priv_list['page-interfaces-lagg-edit']['match'] = array();
+$priv_list['page-interfaces-lagg-edit']['match'][] = "interfaces_lagg_edit.php*";
+
+$priv_list['page-interfaces-ppps'] = array();
+$priv_list['page-interfaces-ppps']['name'] = gettext("WebCfg - Interfaces: ppps page");
+$priv_list['page-interfaces-ppps']['descr'] = gettext("Allow access to the 'Interfaces: ppps' page.");
+$priv_list['page-interfaces-ppps']['match'] = array();
+$priv_list['page-interfaces-ppps']['match'][] = "interfaces_ppps.php*";
+
+$priv_list['page-interfaces-ppps-edit'] = array();
+$priv_list['page-interfaces-ppps-edit']['name'] = gettext("WebCfg - Interfaces: PPPs: Edit page");
+$priv_list['page-interfaces-ppps-edit']['descr'] = gettext("Allow access to the 'Interfaces: PPPs: Edit' page.");
+$priv_list['page-interfaces-ppps-edit']['match'] = array();
+$priv_list['page-interfaces-ppps-edit']['match'][] = "interfaces_ppps_edit.php*";
+
+$priv_list['page-interfaces-qinq'] = array();
+$priv_list['page-interfaces-qinq']['name'] = gettext("WebCfg - Interfaces: QinQ page");
+$priv_list['page-interfaces-qinq']['descr'] = gettext("Allow access to the 'Interfaces: QinQ' page.");
+$priv_list['page-interfaces-qinq']['match'] = array();
+$priv_list['page-interfaces-qinq']['match'][] = "interfaces_qinq.php*";
+
+$priv_list['page-interfaces-qinq-edit'] = array();
+$priv_list['page-interfaces-qinq-edit']['name'] = gettext("Interfaces: QinQ: Edit page");
+$priv_list['page-interfaces-qinq-edit']['descr'] = gettext("Allow access to 'Interfaces: QinQ: Edit' page");
+$priv_list['page-interfaces-qinq-edit']['match'] = array();
+$priv_list['page-interfaces-qinq-edit']['match'][] = "interfaces_qinq_edit.php*";
+
+$priv_list['page-interfaces-vlan'] = array();
+$priv_list['page-interfaces-vlan']['name'] = gettext("WebCfg - Interfaces: VLAN page");
+$priv_list['page-interfaces-vlan']['descr'] = gettext("Allow access to the 'Interfaces: VLAN' page.");
+$priv_list['page-interfaces-vlan']['match'] = array();
+$priv_list['page-interfaces-vlan']['match'][] = "interfaces_vlan.php*";
+
+$priv_list['page-interfaces-vlan-edit'] = array();
+$priv_list['page-interfaces-vlan-edit']['name'] = gettext("WebCfg - Interfaces: VLAN: Edit page");
+$priv_list['page-interfaces-vlan-edit']['descr'] = gettext("Allow access to the 'Interfaces: VLAN: Edit' page.");
+$priv_list['page-interfaces-vlan-edit']['match'] = array();
+$priv_list['page-interfaces-vlan-edit']['match'][] = "interfaces_vlan_edit.php*";
+
+$priv_list['page-interfaces-wireless'] = array();
+$priv_list['page-interfaces-wireless']['name'] = gettext("WebCfg - Interfaces: Wireless page");
+$priv_list['page-interfaces-wireless']['descr'] = gettext("Allow access to the 'Interfaces: Wireless' page.");
+$priv_list['page-interfaces-wireless']['match'] = array();
+$priv_list['page-interfaces-wireless']['match'][] = "interfaces_wireless.php*";
+
+$priv_list['page-interfaces-wireless-edit'] = array();
+$priv_list['page-interfaces-wireless-edit']['name'] = gettext("WebCfg - Interfaces: Wireless edit page");
+$priv_list['page-interfaces-wireless-edit']['descr'] = gettext("Allow access to the 'Interfaces: Wireless : Edit' page.");
+$priv_list['page-interfaces-wireless-edit']['match'] = array();
+$priv_list['page-interfaces-wireless-edit']['match'][] = "interfaces_wireless_edit.php*";
+
+$priv_list['page-system-license'] = array();
+$priv_list['page-system-license']['name'] = gettext("WebCfg - System: License page");
+$priv_list['page-system-license']['descr'] = gettext("Allow access to the 'System: License' page.");
+$priv_list['page-system-license']['match'] = array();
+$priv_list['page-system-license']['match'][] = "license.php*";
+
+$priv_list['page-services-loadbalancer-monitor'] = array();
+$priv_list['page-services-loadbalancer-monitor']['name'] = gettext("WebCfg - Services: Load Balancer: Monitors page");
+$priv_list['page-services-loadbalancer-monitor']['descr'] = gettext("Allow access to the 'Services: Load Balancer: Monitors' page.");
+$priv_list['page-services-loadbalancer-monitor']['match'] = array();
+$priv_list['page-services-loadbalancer-monitor']['match'][] = "load_balancer_monitor.php*";
+
+$priv_list['page-services-loadbalancer-monitor-edit'] = array();
+$priv_list['page-services-loadbalancer-monitor-edit']['name'] = gettext("WebCfg - Services: Load Balancer: Monitor: Edit page");
+$priv_list['page-services-loadbalancer-monitor-edit']['descr'] = gettext("Allow access to the 'Services: Load Balancer: Monitor: Edit' page.");
+$priv_list['page-services-loadbalancer-monitor-edit']['match'] = array();
+$priv_list['page-services-loadbalancer-monitor-edit']['match'][] = "load_balancer_monitor_edit.php*";
+
+$priv_list['page-loadbalancer-pool'] = array();
+$priv_list['page-loadbalancer-pool']['name'] = gettext("WebCfg - Load Balancer: Pool page");
+$priv_list['page-loadbalancer-pool']['descr'] = gettext("Allow access to the 'Load Balancer: Pool' page.");
+$priv_list['page-loadbalancer-pool']['match'] = array();
+$priv_list['page-loadbalancer-pool']['match'][] = "load_balancer_pool.php*";
+
+$priv_list['page-loadbalancer-pool-edit'] = array();
+$priv_list['page-loadbalancer-pool-edit']['name'] = gettext("WebCfg - Load Balancer: Pool: Edit page");
+$priv_list['page-loadbalancer-pool-edit']['descr'] = gettext("Allow access to the 'Load Balancer: Pool: Edit' page.");
+$priv_list['page-loadbalancer-pool-edit']['match'] = array();
+$priv_list['page-loadbalancer-pool-edit']['match'][] = "load_balancer_pool_edit.php*";
+
+$priv_list['page-services-loadbalancer-setting'] = array();
+$priv_list['page-services-loadbalancer-setting']['name'] = gettext("Webcfg - Services: Load Balancer: setting page");
+$priv_list['page-services-loadbalancer-setting']['descr'] = gettext("Allow access to the 'Settings: Load Balancer: Settings' page.");
+$priv_list['page-services-loadbalancer-setting']['match'] = array();
+$priv_list['page-services-loadbalancer-setting']['match'][] = "load_balancer_setting.php*";
+
+$priv_list['page-services-loadbalancer-virtualservers'] = array();
+$priv_list['page-services-loadbalancer-virtualservers']['name'] = gettext("WebCfg - Services: Load Balancer: Virtual Servers page");
+$priv_list['page-services-loadbalancer-virtualservers']['descr'] = gettext("Allow access to the 'Services: Load Balancer: Virtual Servers' page.");
+$priv_list['page-services-loadbalancer-virtualservers']['match'] = array();
+$priv_list['page-services-loadbalancer-virtualservers']['match'][] = "load_balancer_virtual_server.php*";
+
+$priv_list['page-services-ntpd'] = array();
+$priv_list['page-services-ntpd']['name'] = gettext("Webcfg - Services: NTP");
+$priv_list['page-services-ntpd']['descr'] = gettext("Allow access to the 'Services: NTP' page.");
+$priv_list['page-services-ntpd']['match'] = array();
+$priv_list['page-services-ntpd']['match'][] = "services_ntpd.php*";
+
+$priv_list['page-services-ntp-gps'] = array();
+$priv_list['page-services-ntp-gps']['name'] = gettext("Webcfg - Status: NTP GPS page");
+$priv_list['page-services-ntp-gps']['descr'] = gettext("Allow access to the 'Status: NTP Serial GPS' page.");
+$priv_list['page-services-ntp-gps']['match'] = array();
+$priv_list['page-services-ntp-gps']['match'][] = "status_ntpd_gps.php*";
+
+$priv_list['page-services-ntp-pps'] = array();
+$priv_list['page-services-ntp-pps']['name'] = gettext("Webcfg - Status: NTP PPS page");
+$priv_list['page-services-ntp-pps']['descr'] = gettext("Allow access to the 'Status: NTP PPS' page.");
+$priv_list['page-services-ntp-pps']['match'] = array();
+$priv_list['page-services-ntp-pps']['match'][] = "status_ntpd_pps.php*";
+
+$priv_list['page-loadbalancer-virtualserver-edit'] = array();
+$priv_list['page-loadbalancer-virtualserver-edit']['name'] = gettext("WebCfg - Load Balancer: Virtual Server: Edit page");
+$priv_list['page-loadbalancer-virtualserver-edit']['descr'] = gettext("Allow access to the 'Load Balancer: Virtual Server: Edit' page.");
+$priv_list['page-loadbalancer-virtualserver-edit']['match'] = array();
+$priv_list['page-loadbalancer-virtualserver-edit']['match'][] = "load_balancer_virtual_server_edit.php*";
+
+$priv_list['page-package-settings'] = array();
+$priv_list['page-package-settings']['name'] = gettext("WebCfg - Package: Settings page");
+$priv_list['page-package-settings']['descr'] = gettext("Allow access to the 'Package: Settings' page.");
+$priv_list['page-package-settings']['match'] = array();
+$priv_list['page-package-settings']['match'][] = "pkg.php*";
+
+$priv_list['page-package-edit'] = array();
+$priv_list['page-package-edit']['name'] = gettext("WebCfg - Package: Edit page");
+$priv_list['page-package-edit']['descr'] = gettext("Allow access to the 'Package: Edit' page.");
+$priv_list['page-package-edit']['match'] = array();
+$priv_list['page-package-edit']['match'][] = "pkg_edit.php*";
+
+$priv_list['page-system-packagemanager'] = array();
+$priv_list['page-system-packagemanager']['name'] = gettext("WebCfg - System: Package Manager page");
+$priv_list['page-system-packagemanager']['descr'] = gettext("Allow access to the 'System: Package Manager' page.");
+$priv_list['page-system-packagemanager']['match'] = array();
+$priv_list['page-system-packagemanager']['match'][] = "pkg_mgr.php*";
+
+$priv_list['page-system-packagemanager-installpackage'] = array();
+$priv_list['page-system-packagemanager-installpackage']['name'] = gettext("WebCfg - System: Package Manager: Install Package page");
+$priv_list['page-system-packagemanager-installpackage']['descr'] = gettext("Allow access to the 'System: Package Manager: Install Package' page.");
+$priv_list['page-system-packagemanager-installpackage']['match'] = array();
+$priv_list['page-system-packagemanager-installpackage']['match'][] = "pkg_mgr_install.php*";
+
+$priv_list['page-system-packagemanager-installed'] = array();
+$priv_list['page-system-packagemanager-installed']['name'] = gettext("WebCfg - System: Package Manager: Installed page");
+$priv_list['page-system-packagemanager-installed']['descr'] = gettext("Allow access to the 'System: Package Manager: Installed' page.");
+$priv_list['page-system-packagemanager-installed']['match'] = array();
+$priv_list['page-system-packagemanager-installed']['match'][] = "pkg_mgr_installed.php*";
+
+$priv_list['page-pkg-mgr-settings'] = array();
+$priv_list['page-pkg-mgr-settings']['name'] = gettext("WebCfg - Packages: Settings page");
+$priv_list['page-pkg-mgr-settings']['descr'] = gettext("Allow access to the 'Packages: Settings' page.");
+$priv_list['page-pkg-mgr-settings']['match'] = array();
+$priv_list['page-pkg-mgr-settings']['match'][] = "pkg_mgr_settings.php*";
+
+$priv_list['page-diagnostics-rebootsystem'] = array();
+$priv_list['page-diagnostics-rebootsystem']['name'] = gettext("WebCfg - Diagnostics: Reboot System page");
+$priv_list['page-diagnostics-rebootsystem']['descr'] = gettext("Allow access to the 'Diagnostics: Reboot System' page.");
+$priv_list['page-diagnostics-rebootsystem']['match'] = array();
+$priv_list['page-diagnostics-rebootsystem']['match'][] = "reboot.php*";
+
+$priv_list['page-diagnostics-restart-httpd'] = array();
+$priv_list['page-diagnostics-restart-httpd']['name'] = gettext("WebCfg - Diagnostics: Restart HTTPD : System page");
+$priv_list['page-diagnostics-restart-httpd']['descr'] = gettext("Allow access to the 'Diagnostics: Restart HTTPD: System' page.");
+$priv_list['page-diagnostics-restart-httpd']['match'] = array();
+$priv_list['page-diagnostics-restart-httpd']['match'][] = "restart_httpd.php*";
+
+$priv_list['page-services-captiveportal'] = array();
+$priv_list['page-services-captiveportal']['name'] = gettext("WebCfg - Services: Captive portal page");
+$priv_list['page-services-captiveportal']['descr'] = gettext("Allow access to the 'Services: Captive portal' page.");
+$priv_list['page-services-captiveportal']['match'] = array();
+$priv_list['page-services-captiveportal']['match'][] = "services_captiveportal.php*";
+
+$priv_list['page-services-captiveportal-filemanager'] = array();
+$priv_list['page-services-captiveportal-filemanager']['name'] = gettext("WebCfg - Services: Captive portal: File Manager page");
+$priv_list['page-services-captiveportal-filemanager']['descr'] = gettext("Allow access to the 'Services: Captive portal: File Manager' page.");
+$priv_list['page-services-captiveportal-filemanager']['match'] = array();
+$priv_list['page-services-captiveportal-filemanager']['match'][] = "services_captiveportal_filemanager.php*";
+
+$priv_list['page-services-captiveportal-allowedips'] = array();
+$priv_list['page-services-captiveportal-allowedips']['name'] = gettext("WebCfg - Services: Captive portal: Allowed IPs page");
+$priv_list['page-services-captiveportal-allowedips']['descr'] = gettext("Allow access to the 'Services: Captive portal: Allowed IPs' page.");
+$priv_list['page-services-captiveportal-allowedips']['match'] = array();
+$priv_list['page-services-captiveportal-allowedips']['match'][] = "services_captiveportal_ip.php*";
+
+$priv_list['page-services-captiveportal-editallowedips'] = array();
+$priv_list['page-services-captiveportal-editallowedips']['name'] = gettext("WebCfg - Services: Captive portal: Edit Allowed IPs page");
+$priv_list['page-services-captiveportal-editallowedips']['descr'] = gettext("Allow access to the 'Services: Captive portal: Edit Allowed IPs' page.");
+$priv_list['page-services-captiveportal-editallowedips']['match'] = array();
+$priv_list['page-services-captiveportal-editallowedips']['match'][] = "services_captiveportal_ip_edit.php*";
+
+$priv_list['page-services-captiveportal-macaddresses'] = array();
+$priv_list['page-services-captiveportal-macaddresses']['name'] = gettext("WebCfg - Services: Captive portal: Mac Addresses page");
+$priv_list['page-services-captiveportal-macaddresses']['descr'] = gettext("Allow access to the 'Services: Captive portal: Mac Addresses' page.");
+$priv_list['page-services-captiveportal-macaddresses']['match'] = array();
+$priv_list['page-services-captiveportal-macaddresses']['match'][] = "services_captiveportal_mac.php*";
+
+$priv_list['page-services-captiveportal-editmacaddresses'] = array();
+$priv_list['page-services-captiveportal-editmacaddresses']['name'] = gettext("WebCfg - Services: Captive portal: Edit MAC Addresses page");
+$priv_list['page-services-captiveportal-editmacaddresses']['descr'] = gettext("Allow access to the 'Services: Captive portal: Edit MAC Addresses' page.");
+$priv_list['page-services-captiveportal-editmacaddresses']['match'] = array();
+$priv_list['page-services-captiveportal-editmacaddresses']['match'][] = "services_captiveportal_mac_edit.php*";
+
+$priv_list['page-services-captiveportal-allowedhostnames'] = array();
+$priv_list['page-services-captiveportal-allowedhostnames']['name'] = gettext("WebCfg - Services: Captive portal: Allowed Hostnames page");
+$priv_list['page-services-captiveportal-allowedhostnames']['descr'] = gettext("Allow access to the 'Services: Captive portal: Allowed Hostnames' page.");
+$priv_list['page-services-captiveportal-allowedhostnames']['match'] = array();
+$priv_list['page-services-captiveportal-allowedhostnames']['match'][] = "services_captiveportal_hostname.php*";
+
+$priv_list['page-services-captiveportal-editallowedhostnames'] = array();
+$priv_list['page-services-captiveportal-editallowedhostnames']['name'] = gettext("WebCfg - Services: Captive portal: Edit Allowed Hostnames page");
+$priv_list['page-services-captiveportal-editallowedhostnames']['descr'] = gettext("Allow access to the 'Services: Captive portal: Allowed Hostnames' page.");
+$priv_list['page-services-captiveportal-editallowedhostnames']['match'] = array();
+$priv_list['page-services-captiveportal-editallowedhostnames']['match'][] = "services_captiveportal_hostname_edit.php*";
+
+$priv_list['page-services-captiveportal-editzones'] = array();
+$priv_list['page-services-captiveportal-editzones']['name'] = gettext("Webcfg - Services: Captive portal: Edit Zones page");
+$priv_list['page-services-captiveportal-editzones']['descr'] = gettext("Allow access to the 'Services: Captive portal: Edit Zones' page.");
+$priv_list['page-services-captiveportal-editzones']['match'] = array();
+$priv_list['page-services-captiveportal-editzones']['match'][] = "services_captiveportal_zones_edit.php*";
+
+$priv_list['page-services-captiveportal-vouchers'] = array();
+$priv_list['page-services-captiveportal-vouchers']['name'] = gettext("WebCfg - Services: Captive portal Vouchers page");
+$priv_list['page-services-captiveportal-vouchers']['descr'] = gettext("Allow access to the 'Services: Captive portal Vouchers' page.");
+$priv_list['page-services-captiveportal-vouchers']['match'] = array();
+$priv_list['page-services-captiveportal-vouchers']['match'][] = "services_captiveportal_vouchers.php*";
+
+$priv_list['page-services-captiveportal-voucher-edit'] = array();
+$priv_list['page-services-captiveportal-voucher-edit']['name'] = "WebCfg - Services: Captive portal Voucher Rolls page";
+$priv_list['page-services-captiveportal-voucher-edit']['descr'] = "Allow access to the 'Services: Captive portal Edit Voucher Rolls' page.";
+$priv_list['page-services-captiveportal-voucher-edit']['match'] = array();
+$priv_list['page-services-captiveportal-voucher-edit']['match'][] = "services_captiveportal_vouchers_edit.php*";
+
+$priv_list['page-services-captiveportal-zones'] = array();
+$priv_list['page-services-captiveportal-zones']['name'] = gettext("WebCfg - Services: Captive portal Zones page");
+$priv_list['page-services-captiveportal-zones']['descr'] = gettext("Allow access to the 'Services: Captive portal Zones' page.");
+$priv_list['page-services-captiveportal-zones']['match'] = array();
+$priv_list['page-services-captiveportal-zones']['match'][] = "services_captiveportal_zones.php*";
+
+$priv_list['page-services-dhcpserver'] = array();
+$priv_list['page-services-dhcpserver']['name'] = gettext("WebCfg - Services: DHCP server page");
+$priv_list['page-services-dhcpserver']['descr'] = gettext("Allow access to the 'Services: DHCP server' page.");
+$priv_list['page-services-dhcpserver']['match'] = array();
+$priv_list['page-services-dhcpserver']['match'][] = "services_dhcp.php*";
+
+$priv_list['page-services-dhcpserver-editstaticmapping'] = array();
+$priv_list['page-services-dhcpserver-editstaticmapping']['name'] = gettext("WebCfg - Services: DHCP Server : Edit static mapping page");
+$priv_list['page-services-dhcpserver-editstaticmapping']['descr'] = gettext("Allow access to the 'Services: DHCP Server : Edit static mapping' page.");
+$priv_list['page-services-dhcpserver-editstaticmapping']['match'] = array();
+$priv_list['page-services-dhcpserver-editstaticmapping']['match'][] = "services_dhcp_edit.php*";
+
+$priv_list['page-services-dhcprelay'] = array();
+$priv_list['page-services-dhcprelay']['name'] = gettext("WebCfg - Services: DHCP Relay page");
+$priv_list['page-services-dhcprelay']['descr'] = gettext("Allow access to the 'Services: DHCP Relay' page.");
+$priv_list['page-services-dhcprelay']['match'] = array();
+$priv_list['page-services-dhcprelay']['match'][] = "services_dhcp_relay.php*";
+
+$priv_list['page-services-dhcpv6server'] = array();
+$priv_list['page-services-dhcpv6server']['name'] = gettext("Webcfg - Services: DHCPv6 server page");
+$priv_list['page-services-dhcpv6server']['descr'] = gettext("Allow access to the 'Services: DHCPv6 server' page.");
+$priv_list['page-services-dhcpv6server']['match'] = array();
+$priv_list['page-services-dhcpv6server']['match'][] = "services_dhcpv6.php*";
+
+$priv_list['page-services-dhcpserverv6-editstaticmapping'] = array();
+$priv_list['page-services-dhcpserverv6-editstaticmapping']['name'] = gettext("Webcfg - Services: DHCPv6 Server : Edit static mapping page");
+$priv_list['page-services-dhcpserverv6-editstaticmapping']['descr'] = gettext("Allow access to the 'Services: DHCPv6 Server : Edit static mapping' page.");
+$priv_list['page-services-dhcpserverv6-editstaticmapping']['match'] = array();
+$priv_list['page-services-dhcpserverv6-editstaticmapping']['match'][] = "services_dhcpv6_edit.php*";
+
+$priv_list['page-services-dhcpv6relay'] = array();
+$priv_list['page-services-dhcpv6relay']['name'] = gettext("Webcfg - Services: DHCPv6 Relay page");
+$priv_list['page-services-dhcpv6relay']['descr'] = gettext("Allow access to the 'Services: DHCPv6 Relay' page.");
+$priv_list['page-services-dhcpv6relay']['match'] = array();
+$priv_list['page-services-dhcpv6relay']['match'][] = "services_dhcpv6_relay.php*";
+
+$priv_list['page-services-dnsforwarder'] = array();
+$priv_list['page-services-dnsforwarder']['name'] = gettext("WebCfg - Services: DNS Forwarder page");
+$priv_list['page-services-dnsforwarder']['descr'] = gettext("Allow access to the 'Services: DNS Forwarder' page.");
+$priv_list['page-services-dnsforwarder']['match'] = array();
+$priv_list['page-services-dnsforwarder']['match'][] = "services_dnsmasq.php*";
+
+$priv_list['page-services-dnsforwarder-editdomainoverride'] = array();
+$priv_list['page-services-dnsforwarder-editdomainoverride']['name'] = gettext("WebCfg - Services: DNS Forwarder: Edit Domain Override page");
+$priv_list['page-services-dnsforwarder-editdomainoverride']['descr'] = gettext("Allow access to the 'Services: DNS Forwarder: Edit Domain Override' page.");
+$priv_list['page-services-dnsforwarder-editdomainoverride']['match'] = array();
+$priv_list['page-services-dnsforwarder-editdomainoverride']['match'][] = "services_dnsmasq_domainoverride_edit.php*";
+
+$priv_list['page-services-dnsforwarder-edithost'] = array();
+$priv_list['page-services-dnsforwarder-edithost']['name'] = gettext("WebCfg - Services: DNS Forwarder: Edit host page");
+$priv_list['page-services-dnsforwarder-edithost']['descr'] = gettext("Allow access to the 'Services: DNS Forwarder: Edit host' page.");
+$priv_list['page-services-dnsforwarder-edithost']['match'] = array();
+$priv_list['page-services-dnsforwarder-edithost']['match'][] = "services_dnsmasq_edit.php*";
+
+$priv_list['page-services-dnsresolver'] = array();
+$priv_list['page-services-dnsresolver']['name'] = gettext("WebCfg - Services: DNS Resolver page");
+$priv_list['page-services-dnsresolver']['descr'] = gettext("Allow access to the 'Services: DNS Resolver' page.");
+$priv_list['page-services-dnsresolver']['match'] = array();
+$priv_list['page-services-dnsresolver']['match'][] = "services_unbound.php*";
+
+$priv_list['page-services-dnsresolver-advanced'] = array();
+$priv_list['page-services-dnsresolver-advanced']['name'] = gettext("WebCfg - Services: DNS Resolver: Advanced page");
+$priv_list['page-services-dnsresolver-advanced']['descr'] = gettext("Allow access to the 'Services: DNS Resolver: Advanced' page.");
+$priv_list['page-services-dnsresolver-advanced']['match'] = array();
+$priv_list['page-services-dnsresolver-advanced']['match'][] = "services_unbound_advanced.php*";
+
+$priv_list['page-services-dnsresolver-acls'] = array();
+$priv_list['page-services-dnsresolver-acls']['name'] = gettext("WebCfg - Services: DNS Resolver: Access Lists page");
+$priv_list['page-services-dnsresolver-acls']['descr'] = gettext("Allow access to the 'Services: DNS Resolver: Access Lists' page.");
+$priv_list['page-services-dnsresolver-acls']['match'] = array();
+$priv_list['page-services-dnsresolver-acls']['match'][] = "services_unbound_acls.php*";
+
+$priv_list['page-services-dnsresolver-editacls'] = array();
+$priv_list['page-services-dnsresolver-editacls']['name'] = gettext("WebCfg - Services: DNS Resolver: Access Lists: Edit page");
+$priv_list['page-services-dnsresolver-editacls']['descr'] = gettext("Allow access to the 'Services: DNS Resolver: Access Lists: Edit' page.");
+$priv_list['page-services-dnsresolver-editacls']['match'] = array();
+$priv_list['page-services-dnsresolver-editacls']['match'][] = "services_unbound_acls_edit.php*";
+
+$priv_list['page-services-dnsresolver-editdomainoverride'] = array();
+$priv_list['page-services-dnsresolver-editdomainoverride']['name'] = gettext("WebCfg - Services: DNS Resolver: Edit Domain Override page");
+$priv_list['page-services-dnsresolver-editdomainoverride']['descr'] = gettext("Allow access to the 'Services: DNS Resolver: Edit Domain Override' page.");
+$priv_list['page-services-dnsresolver-editdomainoverride']['match'] = array();
+$priv_list['page-services-dnsresolver-editdomainoverride']['match'][] = "services_unbound_domainoverride_edit.php*";
+
+$priv_list['page-services-dnsresolver-edithost'] = array();
+$priv_list['page-services-dnsresolver-edithost']['name'] = gettext("WebCfg - Services: DNS Resolver: Edit host page");
+$priv_list['page-services-dnsresolver-edithost']['descr'] = gettext("Allow access to the 'Services: DNS Resolver: Edit host' page.");
+$priv_list['page-services-dnsresolver-edithost']['match'] = array();
+$priv_list['page-services-dnsresolver-edithost']['match'][] = "services_unbound_host_edit.php*";
+
+$priv_list['page-services-dynamicdnsclients'] = array();
+$priv_list['page-services-dynamicdnsclients']['name'] = gettext("WebCfg - Services: Dynamic DNS clients page");
+$priv_list['page-services-dynamicdnsclients']['descr'] = gettext("Allow access to the 'Services: Dynamic DNS clients' page.");
+$priv_list['page-services-dynamicdnsclients']['match'] = array();
+$priv_list['page-services-dynamicdnsclients']['match'][] = "services_dyndns.php*";
+
+$priv_list['page-services-dynamicdnsclient'] = array();
+$priv_list['page-services-dynamicdnsclient']['name'] = gettext("WebCfg - Services: Dynamic DNS client page");
+$priv_list['page-services-dynamicdnsclient']['descr'] = gettext("Allow access to the 'Services: Dynamic DNS client' page.");
+$priv_list['page-services-dynamicdnsclient']['match'] = array();
+$priv_list['page-services-dynamicdnsclient']['match'][] = "services_dyndns_edit.php*";
+
+$priv_list['page-services-igmpproxy'] = array();
+$priv_list['page-services-igmpproxy']['name'] = gettext("WebCfg - Services: Igmpproxy page");
+$priv_list['page-services-igmpproxy']['descr'] = gettext("Allow access to the 'Services: Igmpproxy' page.");
+$priv_list['page-services-igmpproxy']['match'] = array();
+$priv_list['page-services-igmpproxy']['match'][] = "services_igmpproxy.php*";
+
+$priv_list['page-services-igmpproxy-edit'] = array();
+$priv_list['page-services-igmpproxy-edit']['name'] = gettext("Firewall: Igmpproxy: Edit page");
+$priv_list['page-services-igmpproxy-edit']['descr'] = gettext("Allow access to the 'Services: Igmpproxy: Edit' page.");
+$priv_list['page-services-igmpproxy-edit']['match'] = array();
+$priv_list['page-services-igmpproxy-edit']['match'][] = "services_igmpproxy_edit.php*";
+
+$priv_list['page-services-rfc2136clients'] = array();
+$priv_list['page-services-rfc2136clients']['name'] = gettext("WebCfg - Services: RFC 2136 clients page");
+$priv_list['page-services-rfc2136clients']['descr'] = gettext("Allow access to the 'Services: RFC 2136 clients' page.");
+$priv_list['page-services-rfc2136clients']['match'] = array();
+$priv_list['page-services-rfc2136clients']['match'][] = "services_rfc2136.php*";
+
+$priv_list['page-services-router-advertisements'] = array();
+$priv_list['page-services-router-advertisements']['name'] = gettext("Webcfg - Services: Router Advertisements page");
+$priv_list['page-services-router-advertisements']['descr'] = gettext("Allow access to the 'Services: Router Advertisements' page.");
+$priv_list['page-services-router-advertisements']['match'] = array();
+$priv_list['page-services-router-advertisements']['match'][] = "services_router_advertisements.php*";
+
+$priv_list['page-services-snmp'] = array();
+$priv_list['page-services-snmp']['name'] = gettext("WebCfg - Services: SNMP page");
+$priv_list['page-services-snmp']['descr'] = gettext("Allow access to the 'Services: SNMP' page.");
+$priv_list['page-services-snmp']['match'] = array();
+$priv_list['page-services-snmp']['match'][] = "services_snmp.php*";
+
+$priv_list['page-services-wakeonlan'] = array();
+$priv_list['page-services-wakeonlan']['name'] = gettext("WebCfg - Services: Wake on LAN page");
+$priv_list['page-services-wakeonlan']['descr'] = gettext("Allow access to the 'Services: Wake on LAN' page.");
+$priv_list['page-services-wakeonlan']['match'] = array();
+$priv_list['page-services-wakeonlan']['match'][] = "services_wol.php*";
+
+$priv_list['page-services-wakeonlan-edit'] = array();
+$priv_list['page-services-wakeonlan-edit']['name'] = gettext("WebCfg - Services: Wake on LAN: Edit page");
+$priv_list['page-services-wakeonlan-edit']['descr'] = gettext("Allow access to the 'Services: Wake on LAN: Edit' page.");
+$priv_list['page-services-wakeonlan-edit']['match'] = array();
+$priv_list['page-services-wakeonlan-edit']['match'][] = "services_wol_edit.php*";
+
+$priv_list['page-diagnostics-cpuutilization'] = array();
+$priv_list['page-diagnostics-cpuutilization']['name'] = gettext("WebCfg - Diagnostics: CPU Utilization page");
+$priv_list['page-diagnostics-cpuutilization']['descr'] = gettext("Allow access to the 'Diagnostics: CPU Utilization' page.");
+$priv_list['page-diagnostics-cpuutilization']['match'] = array();
+$priv_list['page-diagnostics-cpuutilization']['match'][] = "stats.php*";
+
+$priv_list['page-hidden-detailedstatus'] = array();
+$priv_list['page-hidden-detailedstatus']['name'] = gettext("WebCfg - Hidden: Detailed Status page");
+$priv_list['page-hidden-detailedstatus']['descr'] = gettext("Allow access to the 'Hidden: Detailed Status' page.");
+$priv_list['page-hidden-detailedstatus']['match'] = array();
+$priv_list['page-hidden-detailedstatus']['match'][] = "status.php*";
+
+$priv_list['page-status-captiveportal'] = array();
+$priv_list['page-status-captiveportal']['name'] = gettext("WebCfg - Status: Captive portal page");
+$priv_list['page-status-captiveportal']['descr'] = gettext("Allow access to the 'Status: Captive portal' page.");
+$priv_list['page-status-captiveportal']['match'] = array();
+$priv_list['page-status-captiveportal']['match'][] = "status_captiveportal.php*";
+
+$priv_list['page-status-captiveportal-expire'] = array();
+$priv_list['page-status-captiveportal-expire']['name'] = gettext("Webcfg - Status: Captive portal Expire Vouchers page");
+$priv_list['page-status-captiveportal-expire']['descr'] = gettext("Allow access to the 'Status: Captive portal Expire Vouchers' page.");
+$priv_list['page-status-captiveportal-expire']['match'] = array();
+$priv_list['page-status-captiveportal-expire']['match'][] = "status_captiveportal_expire.php*";
+
+$priv_list['page-status-captiveportal-test'] = array();
+$priv_list['page-status-captiveportal-test']['name'] = gettext("WebCfg - Status: Captive portal Test Vouchers page");
+$priv_list['page-status-captiveportal-test']['descr'] = gettext("Allow access to the 'Status: Captive portal Test Vouchers' page.");
+$priv_list['page-status-captiveportal-test']['match'] = array();
+$priv_list['page-status-captiveportal-test']['match'][] = "status_captiveportal_test.php*";
+
+$priv_list['page-status-captiveportal-voucher-rolls'] = array();
+$priv_list['page-status-captiveportal-voucher-rolls']['name'] = gettext("WebCfg - Status: Captive portal Voucher Rolls page");
+$priv_list['page-status-captiveportal-voucher-rolls']['descr'] = gettext("Allow access to the 'Status: Captive portal Voucher Rolls' page.");
+$priv_list['page-status-captiveportal-voucher-rolls']['match'] = array();
+$priv_list['page-status-captiveportal-voucher-rolls']['match'][] = "status_captiveportal_voucher_rolls.php*";
+
+$priv_list['page-status-captiveportal-vouchers'] = array();
+$priv_list['page-status-captiveportal-vouchers']['name'] = gettext("WebCfg - Status: Captive portal Vouchers page");
+$priv_list['page-status-captiveportal-vouchers']['descr'] = gettext("Allow access to the 'Status: Captive portal Vouchers' page.");
+$priv_list['page-status-captiveportal-vouchers']['match'] = array();
+$priv_list['page-status-captiveportal-vouchers']['match'][] = "status_captiveportal_vouchers.php*";
+
+$priv_list['page-status-dhcpleases'] = array();
+$priv_list['page-status-dhcpleases']['name'] = gettext("WebCfg - Status: DHCP leases page");
+$priv_list['page-status-dhcpleases']['descr'] = gettext("Allow access to the 'Status: DHCP leases' page.");
+$priv_list['page-status-dhcpleases']['match'] = array();
+$priv_list['page-status-dhcpleases']['match'][] = "status_dhcp_leases.php*";
+
+$priv_list['page-status-dhcpv6leases'] = array();
+$priv_list['page-status-dhcpv6leases']['name'] = gettext("Webcfg - Status: DHCPv6 leases page");
+$priv_list['page-status-dhcpv6leases']['descr'] = gettext("Allow access to the 'Status: DHCPv6 leases' page.");
+$priv_list['page-status-dhcpv6leases']['match'] = array();
+$priv_list['page-status-dhcpv6leases']['match'][] = "status_dhcpv6_leases.php*";
+
+$priv_list['page-status-filterreloadstatus'] = array();
+$priv_list['page-status-filterreloadstatus']['name'] = gettext("WebCfg - Status: Filter Reload Status page");
+$priv_list['page-status-filterreloadstatus']['descr'] = gettext("Allow access to the 'Status: Filter Reload Status' page.");
+$priv_list['page-status-filterreloadstatus']['match'] = array();
+$priv_list['page-status-filterreloadstatus']['match'][] = "status_filter_reload.php*";
+
+$priv_list['page-status-gatewaygroups'] = array();
+$priv_list['page-status-gatewaygroups']['name'] = gettext("WebCfg - Status: Gateway Groups page");
+$priv_list['page-status-gatewaygroups']['descr'] = gettext("Allow access to the 'Status: Gateway Groups' page.");
+$priv_list['page-status-gatewaygroups']['match'] = array();
+$priv_list['page-status-gatewaygroups']['match'][] = "status_gateway_groups.php*";
+
+$priv_list['page-status-gateways'] = array();
+$priv_list['page-status-gateways']['name'] = gettext("WebCfg - Status: Gateways page");
+$priv_list['page-status-gateways']['descr'] = gettext("Allow access to the 'Status: Gateways' page.");
+$priv_list['page-status-gateways']['match'] = array();
+$priv_list['page-status-gateways']['match'][] = "status_gateways.php*";
+
+$priv_list['page-status-trafficgraph'] = array();
+$priv_list['page-status-trafficgraph']['name'] = gettext("WebCfg - Status: Traffic Graph page");
+$priv_list['page-status-trafficgraph']['descr'] = gettext("Allow access to the 'Status: Traffic Graph' page.");
+$priv_list['page-status-trafficgraph']['match'] = array();
+$priv_list['page-status-trafficgraph']['match'][] = "status_graph.php*";
+$priv_list['page-status-trafficgraph']['match'][] = "bandwidth_by_ip.php*";
+$priv_list['page-status-trafficgraph']['match'][] = "graph.php*";
+$priv_list['page-status-trafficgraph']['match'][] = "ifstats.php*";
+
+$priv_list['page-status-cpuload'] = array();
+$priv_list['page-status-cpuload']['name'] = gettext("WebCfg - Status: CPU load page");
+$priv_list['page-status-cpuload']['descr'] = gettext("Allow access to the 'Status: CPU load' page.");
+$priv_list['page-status-cpuload']['match'] = array();
+$priv_list['page-status-cpuload']['match'][] = "status_graph_cpu.php*";
+
+$priv_list['page-status-interfaces'] = array();
+$priv_list['page-status-interfaces']['name'] = gettext("WebCfg - Status: Interfaces page");
+$priv_list['page-status-interfaces']['descr'] = gettext("Allow access to the 'Status: Interfaces' page.");
+$priv_list['page-status-interfaces']['match'] = array();
+$priv_list['page-status-interfaces']['match'][] = "status_interfaces.php*";
+
+$priv_list['page-status-loadbalancer-pool'] = array();
+$priv_list['page-status-loadbalancer-pool']['name'] = gettext("WebCfg - Status: Load Balancer: Pool page");
+$priv_list['page-status-loadbalancer-pool']['descr'] = gettext("Allow access to the 'Status: Load Balancer: Pool' page.");
+$priv_list['page-status-loadbalancer-pool']['match'] = array();
+$priv_list['page-status-loadbalancer-pool']['match'][] = "status_lb_pool.php*";
+
+$priv_list['page-status-loadbalancer-virtualserver'] = array();
+$priv_list['page-status-loadbalancer-virtualserver']['name'] = gettext("WebCfg - Status: Load Balancer: Virtual Server page");
+$priv_list['page-status-loadbalancer-virtualserver']['descr'] = gettext("Allow access to the 'Status: Load Balancer: Virtual Server' page.");
+$priv_list['page-status-loadbalancer-virtualserver']['match'] = array();
+$priv_list['page-status-loadbalancer-virtualserver']['match'][] = "status_lb_vs.php*";
+
+$priv_list['page-status-openvpn'] = array();
+$priv_list['page-status-openvpn']['name'] = gettext("WebCfg - Status: OpenVPN page");
+$priv_list['page-status-openvpn']['descr'] = gettext("Allow access to the 'Status: OpenVPN' page.");
+$priv_list['page-status-openvpn']['match'] = array();
+$priv_list['page-status-openvpn']['match'][] = "status_openvpn.php*";
+
+$priv_list['page-status-trafficshaper-queues'] = array();
+$priv_list['page-status-trafficshaper-queues']['name'] = gettext("WebCfg - Status: Traffic shaper: Queues page");
+$priv_list['page-status-trafficshaper-queues']['descr'] = gettext("Allow access to the 'Status: Traffic shaper: Queues' page.");
+$priv_list['page-status-trafficshaper-queues']['match'] = array();
+$priv_list['page-status-trafficshaper-queues']['match'][] = "status_queues.php*";
+
+$priv_list['page-status-rrdgraphs'] = array();
+$priv_list['page-status-rrdgraphs']['name'] = gettext("WebCfg - Status: RRD Graphs page");
+$priv_list['page-status-rrdgraphs']['descr'] = gettext("Allow access to the 'Status: RRD Graphs' page.");
+$priv_list['page-status-rrdgraphs']['match'] = array();
+$priv_list['page-status-rrdgraphs']['match'][] = "status_rrd_graph.php*";
+$priv_list['page-status-rrdgraphs']['match'][] = "status_rrd_graph_img.php*";
+
+$priv_list['page-status-rrdgraph-settings'] = array();
+$priv_list['page-status-rrdgraph-settings']['name'] = gettext("WebCfg - Status: RRD Graphs settings page");
+$priv_list['page-status-rrdgraph-settings']['descr'] = gettext("Allow access to the 'Status: RRD Graphs: settings' page.");
+$priv_list['page-status-rrdgraph-settings']['match'] = array();
+$priv_list['page-status-rrdgraph-settings']['match'][] = "status_rrd_graph_settings.php*";
+
+$priv_list['page-status-services'] = array();
+$priv_list['page-status-services']['name'] = gettext("WebCfg - Status: Services page");
+$priv_list['page-status-services']['descr'] = gettext("Allow access to the 'Status: Services' page.");
+$priv_list['page-status-services']['match'] = array();
+$priv_list['page-status-services']['match'][] = "status_services.php*";
+
+$priv_list['page-status-upnpstatus'] = array();
+$priv_list['page-status-upnpstatus']['name'] = gettext("WebCfg - Status: UPnP Status page");
+$priv_list['page-status-upnpstatus']['descr'] = gettext("Allow access to the 'Status: UPnP Status' page.");
+$priv_list['page-status-upnpstatus']['match'] = array();
+$priv_list['page-status-upnpstatus']['match'][] = "status_upnp.php*";
+
+$priv_list['page-diagnostics-wirelessstatus'] = array();
+$priv_list['page-diagnostics-wirelessstatus']['name'] = gettext("WebCfg - Status: Wireless page");
+$priv_list['page-diagnostics-wirelessstatus']['descr'] = gettext("Allow access to the 'Status: Wireless' page.");
+$priv_list['page-diagnostics-wirelessstatus']['match'] = array();
+$priv_list['page-diagnostics-wirelessstatus']['match'][] = "status_wireless.php*";
+
+$priv_list['page-system-generalsetup'] = array();
+$priv_list['page-system-generalsetup']['name'] = gettext("WebCfg - System: General Setup page");
+$priv_list['page-system-generalsetup']['descr'] = gettext("Allow access to the 'System: General Setup' page.");
+$priv_list['page-system-generalsetup']['match'] = array();
+$priv_list['page-system-generalsetup']['match'][] = "system.php*";
+
+$priv_list['page-system-advanced-admin'] = array();
+$priv_list['page-system-advanced-admin']['name'] = gettext("WebCfg - System: Advanced: Admin Access Page");
+$priv_list['page-system-advanced-admin']['descr'] = gettext("Allow access to the 'System: Advanced: Admin Access' page.");
+$priv_list['page-system-advanced-admin']['match'] = array();
+$priv_list['page-system-advanced-admin']['match'][] = "system_advanced_admin.php*";
+
+$priv_list['page-system-advanced-firewall'] = array();
+$priv_list['page-system-advanced-firewall']['name'] = gettext("WebCfg - System: Advanced: Firewall and NAT page");
+$priv_list['page-system-advanced-firewall']['descr'] = gettext("Allow access to the 'System: Advanced: Firewall and NAT' page.");
+$priv_list['page-system-advanced-firewall']['match'] = array();
+$priv_list['page-system-advanced-firewall']['match'][] = "system_advanced_firewall.php*";
+
+$priv_list['page-system-advanced-misc'] = array();
+$priv_list['page-system-advanced-misc']['name'] = gettext("WebCfg - System: Advanced: Miscellaneous page");
+$priv_list['page-system-advanced-misc']['descr'] = gettext("Allow access to the 'System: Advanced: Miscellaneous' page.");
+$priv_list['page-system-advanced-misc']['match'] = array();
+$priv_list['page-system-advanced-misc']['match'][] = "system_advanced_misc.php*";
+
+$priv_list['page-system-advanced-network'] = array();
+$priv_list['page-system-advanced-network']['name'] = gettext("WebCfg - System: Advanced: Networking page");
+$priv_list['page-system-advanced-network']['descr'] = gettext("Allow access to the 'System: Advanced: Networking' page.");
+$priv_list['page-system-advanced-network']['match'] = array();
+$priv_list['page-system-advanced-network']['match'][] = "system_advanced_network.php*";
+
+$priv_list['page-system-advanced-notifications'] = array();
+$priv_list['page-system-advanced-notifications']['name'] = gettext("WebCfg - System: Advanced: Notifications page");
+$priv_list['page-system-advanced-notifications']['descr'] = gettext("Allow access to the 'System: Advanced: Notifications' page.");
+$priv_list['page-system-advanced-notifications']['match'] = array();
+$priv_list['page-system-advanced-notifications']['match'][] = "system_advanced_notifications.php*";
+
+$priv_list['page-system-advanced-sysctl'] = array();
+$priv_list['page-system-advanced-sysctl']['name'] = gettext("WebCfg - System: Advanced: Tunables page");
+$priv_list['page-system-advanced-sysctl']['descr'] = gettext("Allow access to the 'System: Advanced: Tunables' page.");
+$priv_list['page-system-advanced-sysctl']['match'] = array();
+$priv_list['page-system-advanced-sysctl']['match'][] = "system_advanced_sysctl.php*";
+
+$priv_list['page-system-authservers'] = array();
+$priv_list['page-system-authservers']['name'] = gettext("WebCfg - System: Authentication Servers");
+$priv_list['page-system-authservers']['descr'] = gettext("Allow access to the 'System: Authentication Servers' page.");
+$priv_list['page-system-authservers']['match'] = array();
+$priv_list['page-system-authservers']['match'][] = "system_authservers.php*";
+
+$priv_list['page-system-camanager'] = array();
+$priv_list['page-system-camanager']['name'] = gettext("WebCfg - System: CA Manager");
+$priv_list['page-system-camanager']['descr'] = gettext("Allow access to the 'System: CA Manager' page.");
+$priv_list['page-system-camanager']['match'] = array();
+$priv_list['page-system-camanager']['match'][] = "system_camanager.php*";
+
+$priv_list['page-system-certmanager'] = array();
+$priv_list['page-system-certmanager']['name'] = gettext("WebCfg - System: Certificate Manager");
+$priv_list['page-system-certmanager']['descr'] = gettext("Allow access to the 'System: Certificate Manager' page.");
+$priv_list['page-system-certmanager']['match'] = array();
+$priv_list['page-system-certmanager']['match'][] = "system_certmanager.php*";
+
+$priv_list['page-system-crlmanager'] = array();
+$priv_list['page-system-crlmanager']['name'] = gettext("WebCfg - System: CRL Manager");
+$priv_list['page-system-crlmanager']['descr'] = gettext("Allow access to the 'System: CRL Manager' page.");
+$priv_list['page-system-crlmanager']['match'] = array();
+$priv_list['page-system-crlmanager']['match'][] = "system_crlmanager.php*";
+
+$priv_list['page-system-firmware-manualupdate'] = array();
+$priv_list['page-system-firmware-manualupdate']['name'] = gettext("WebCfg - System: Firmware: Manual Update page");
+$priv_list['page-system-firmware-manualupdate']['descr'] = gettext("Allow access to the 'System: Firmware: Manual Update' page.");
+$priv_list['page-system-firmware-manualupdate']['match'] = array();
+$priv_list['page-system-firmware-manualupdate']['match'][] = "system_firmware.php*";
+
+$priv_list['page-system-firmware-checkforupdate'] = array();
+$priv_list['page-system-firmware-checkforupdate']['name'] = gettext("WebCfg - System: Firmware: Check For Update page");
+$priv_list['page-system-firmware-checkforupdate']['descr'] = gettext("Allow access to the 'System: Firmware: Check For Update' page.");
+$priv_list['page-system-firmware-checkforupdate']['match'] = array();
+$priv_list['page-system-firmware-checkforupdate']['match'][] = "system_firmware_auto.php*";
+
+$priv_list['page-system-firmware-autoupdate'] = array();
+$priv_list['page-system-firmware-autoupdate']['name'] = gettext("WebCfg - System: Firmware: Auto Update page");
+$priv_list['page-system-firmware-autoupdate']['descr'] = gettext("Allow access to the 'System: Firmware: Auto Update' page.");
+$priv_list['page-system-firmware-autoupdate']['match'] = array();
+$priv_list['page-system-firmware-autoupdate']['match'][] = "system_firmware_check.php*";
+
+$priv_list['page-system-firmware-settings'] = array();
+$priv_list['page-system-firmware-settings']['name'] = gettext("WebCfg - System: Firmware: Settings page");
+$priv_list['page-system-firmware-settings']['descr'] = gettext("Allow access to the 'System: Firmware: Settings' page.");
+$priv_list['page-system-firmware-settings']['match'] = array();
+$priv_list['page-system-firmware-settings']['match'][] = "system_firmware_settings.php*";
+
+$priv_list['page-system-gatewaygroups'] = array();
+$priv_list['page-system-gatewaygroups']['name'] = gettext("WebCfg - System: Gateway Groups page");
+$priv_list['page-system-gatewaygroups']['descr'] = gettext("Allow access to the 'System: Gateway Groups' page.");
+$priv_list['page-system-gatewaygroups']['match'] = array();
+$priv_list['page-system-gatewaygroups']['match'][] = "system_gateway_groups.php*";
+
+$priv_list['page-system-gateways-editgatewaygroups'] = array();
+$priv_list['page-system-gateways-editgatewaygroups']['name'] = gettext("WebCfg - System: Gateways: Edit Gateway Groups page");
+$priv_list['page-system-gateways-editgatewaygroups']['descr'] = gettext("Allow access to the 'System: Gateways: Edit Gateway Groups' page.");
+$priv_list['page-system-gateways-editgatewaygroups']['match'] = array();
+$priv_list['page-system-gateways-editgatewaygroups']['match'][] = "system_gateway_groups_edit.php*";
+
+$priv_list['page-system-gateways'] = array();
+$priv_list['page-system-gateways']['name'] = gettext("WebCfg - System: Gateways page");
+$priv_list['page-system-gateways']['descr'] = gettext("Allow access to the 'System: Gateways' page.");
+$priv_list['page-system-gateways']['match'] = array();
+$priv_list['page-system-gateways']['match'][] = "system_gateways.php*";
+
+$priv_list['page-system-gateways-editgateway'] = array();
+$priv_list['page-system-gateways-editgateway']['name'] = gettext("WebCfg - System: Gateways: Edit Gateway page");
+$priv_list['page-system-gateways-editgateway']['descr'] = gettext("Allow access to the 'System: Gateways: Edit Gateway' page.");
+$priv_list['page-system-gateways-editgateway']['match'] = array();
+$priv_list['page-system-gateways-editgateway']['match'][] = "system_gateways_edit.php*";
+
+$priv_list['page-system-groupmanager'] = array();
+$priv_list['page-system-groupmanager']['name'] = gettext("WebCfg - System: Group manager page");
+$priv_list['page-system-groupmanager']['descr'] = gettext("Allow access to the 'System: Group manager' page.");
+$priv_list['page-system-groupmanager']['match'] = array();
+$priv_list['page-system-groupmanager']['match'][] = "system_groupmanager.php*";
+
+$priv_list['page-system-groupmanager-addprivs'] = array();
+$priv_list['page-system-groupmanager-addprivs']['name'] = gettext("WebCfg - System: Group Manager: Add Privileges page");
+$priv_list['page-system-groupmanager-addprivs']['descr'] = gettext("Allow access to the 'System: Group Manager: Add Privileges' page.");
+$priv_list['page-system-groupmanager-addprivs']['match'] = array();
+$priv_list['page-system-groupmanager-addprivs']['match'][] = "system_groupmanager_addprivs.php*";
+
+$priv_list['page-system-hasync'] = array();
+$priv_list['page-system-hasync']['name'] = gettext("Webcfg - System: High Availability Sync");
+$priv_list['page-system-hasync']['descr'] = gettext("Allow access to the 'System: High Availability Sync' page.");
+$priv_list['page-system-hasync']['match'] = array();
+$priv_list['page-system-hasync']['match'][] = "system_hasync.php*";
+
+$priv_list['page-system-staticroutes'] = array();
+$priv_list['page-system-staticroutes']['name'] = gettext("WebCfg - System: Static Routes page");
+$priv_list['page-system-staticroutes']['descr'] = gettext("Allow access to the 'System: Static Routes' page.");
+$priv_list['page-system-staticroutes']['match'] = array();
+$priv_list['page-system-staticroutes']['match'][] = "system_routes.php*";
+
+$priv_list['page-system-staticroutes-editroute'] = array();
+$priv_list['page-system-staticroutes-editroute']['name'] = gettext("WebCfg - System: Static Routes: Edit route page");
+$priv_list['page-system-staticroutes-editroute']['descr'] = gettext("Allow access to the 'System: Static Routes: Edit route' page.");
+$priv_list['page-system-staticroutes-editroute']['match'] = array();
+$priv_list['page-system-staticroutes-editroute']['match'][] = "system_routes_edit.php*";
+
+$priv_list['page-system-usermanager'] = array();
+$priv_list['page-system-usermanager']['name'] = gettext("WebCfg - System: User Manager page");
+$priv_list['page-system-usermanager']['descr'] = gettext("Allow access to the 'System: User Manager' page.");
+$priv_list['page-system-usermanager']['match'] = array();
+$priv_list['page-system-usermanager']['match'][] = "system_usermanager.php*";
+
+$priv_list['page-system-usermanager-addprivs'] = array();
+$priv_list['page-system-usermanager-addprivs']['name'] = gettext("WebCfg - System: User Manager: Add Privileges page");
+$priv_list['page-system-usermanager-addprivs']['descr'] = gettext("Allow access to the 'System: User Manager: Add Privileges' page.");
+$priv_list['page-system-usermanager-addprivs']['match'] = array();
+$priv_list['page-system-usermanager-addprivs']['match'][] = "system_usermanager_addprivs.php*";
+
+$priv_list['page-system-usermanager-passwordmg'] = array();
+$priv_list['page-system-usermanager-passwordmg']['name'] = gettext("WebCfg - System: User Password Manager page");
+$priv_list['page-system-usermanager-passwordmg']['descr'] = gettext("Allow access to the 'System: User Password Manager' page.");
+$priv_list['page-system-usermanager-passwordmg']['match'] = array();
+$priv_list['page-system-usermanager-passwordmg']['match'][] = "system_usermanager_passwordmg.php*";
+
+$priv_list['page-system-usermanager-settings'] = array();
+$priv_list['page-system-usermanager-settings']['name'] = gettext("WebCfg - System: User Manager: settings page");
+$priv_list['page-system-usermanager-settings']['descr'] = gettext("Allow access to the 'System: User Manager: settings' page.");
+$priv_list['page-system-usermanager-settings']['match'] = array();
+$priv_list['page-system-usermanager-settings']['match'][] = "system_usermanager_settings.php*";
+
+$priv_list['page-system-usermanager-settings-testldap'] = array();
+$priv_list['page-system-usermanager-settings-testldap']['name'] = gettext("WebCfg - System: User Manager: Settings: Test LDAP page");
+$priv_list['page-system-usermanager-settings-testldap']['descr'] = gettext("Allow access to the 'System: User Manager: Settings: Test LDAP' page.");
+$priv_list['page-system-usermanager-settings-testldap']['match'] = array();
+$priv_list['page-system-usermanager-settings-testldap']['match'][] = "system_usermanager_settings_test.php*";
+
+$priv_list['page-upload_progress'] = array();
+$priv_list['page-upload_progress']['name'] = gettext("WebCfg - System: Firmware: Manual Update page (progress bar)");
+$priv_list['page-upload_progress']['descr'] = gettext("Allow access to the 'System: Firmware: Manual Update: Progress bar' page.");
+$priv_list['page-upload_progress']['match'] = array();
+$priv_list['page-upload_progress']['match'][] = "upload_progress*";
+
+$priv_list['page-hidden-uploadconfiguration'] = array();
+$priv_list['page-hidden-uploadconfiguration']['name'] = gettext("WebCfg - Hidden: Upload Configuration page");
+$priv_list['page-hidden-uploadconfiguration']['descr'] = gettext("Allow access to the 'Hidden: Upload Configuration' page.");
+$priv_list['page-hidden-uploadconfiguration']['match'] = array();
+$priv_list['page-hidden-uploadconfiguration']['match'][] = "uploadconfig.php*";
+
+$priv_list['page-vpn-ipsec'] = array();
+$priv_list['page-vpn-ipsec']['name'] = gettext("WebCfg - VPN: IPsec page");
+$priv_list['page-vpn-ipsec']['descr'] = gettext("Allow access to the 'VPN: IPsec' page.");
+$priv_list['page-vpn-ipsec']['match'] = array();
+$priv_list['page-vpn-ipsec']['match'][] = "vpn_ipsec.php*";
+
+$priv_list['page-vpn-ipsec-listkeys'] = array();
+$priv_list['page-vpn-ipsec-listkeys']['name'] = gettext("WebCfg - VPN: IPsec: Pre-Shared Keys List");
+$priv_list['page-vpn-ipsec-listkeys']['descr'] = gettext("Allow access to the 'VPN: IPsec: Pre-Shared Keys List' page.");
+$priv_list['page-vpn-ipsec-listkeys']['match'] = array();
+$priv_list['page-vpn-ipsec-listkeys']['match'][] = "vpn_ipsec_keys.php*";
+
+$priv_list['page-vpn-ipsec-editkeys'] = array();
+$priv_list['page-vpn-ipsec-editkeys']['name'] = gettext("WebCfg - VPN: IPsec: Edit Pre-Shared Keys");
+$priv_list['page-vpn-ipsec-editkeys']['descr'] = gettext("Allow access to the 'VPN: IPsec: Edit Pre-Shared Keys' page.");
+$priv_list['page-vpn-ipsec-editkeys']['match'] = array();
+$priv_list['page-vpn-ipsec-editkeys']['match'][] = "vpn_ipsec_keys_edit.php*";
+
+$priv_list['page-vpn-ipsec-mobile'] = array();
+$priv_list['page-vpn-ipsec-mobile']['name'] = gettext("WebCfg - VPN: IPsec: Mobile page");
+$priv_list['page-vpn-ipsec-mobile']['descr'] = gettext("Allow access to the 'VPN: IPsec: Mobile' page.");
+$priv_list['page-vpn-ipsec-mobile']['match'] = array();
+$priv_list['page-vpn-ipsec-mobile']['match'][] = "vpn_ipsec_mobile.php*";
+
+$priv_list['page-vpn-ipsec-editphase1'] = array();
+$priv_list['page-vpn-ipsec-editphase1']['name'] = gettext("WebCfg - VPN: IPsec: Edit Phase 1 page");
+$priv_list['page-vpn-ipsec-editphase1']['descr'] = gettext("Allow access to the 'VPN: IPsec: Edit Phase 1' page.");
+$priv_list['page-vpn-ipsec-editphase1']['match'] = array();
+$priv_list['page-vpn-ipsec-editphase1']['match'][] = "vpn_ipsec_phase1.php*";
+
+$priv_list['page-vpn-ipsec-editphase2'] = array();
+$priv_list['page-vpn-ipsec-editphase2']['name'] = gettext("WebCfg - VPN: IPsec: Edit Phase 2 page");
+$priv_list['page-vpn-ipsec-editphase2']['descr'] = gettext("Allow access to the 'VPN: IPsec: Edit Phase 2' page.");
+$priv_list['page-vpn-ipsec-editphase2']['match'] = array();
+$priv_list['page-vpn-ipsec-editphase2']['match'][] = "vpn_ipsec_phase2.php*";
+
+$priv_list['page-vpn-vpnl2tp'] = array();
+$priv_list['page-vpn-vpnl2tp']['name'] = gettext("WebCfg - VPN: VPN L2TP page");
+$priv_list['page-vpn-vpnl2tp']['descr'] = gettext("Allow access to the 'VPN: VPN L2TP' page.");
+$priv_list['page-vpn-vpnl2tp']['match'] = array();
+$priv_list['page-vpn-vpnl2tp']['match'][] = "vpn_l2tp.php*";
+
+$priv_list['page-vpn-vpnl2tp-users'] = array();
+$priv_list['page-vpn-vpnl2tp-users']['name'] = gettext("WebCfg - VPN: VPN L2TP : Users page");
+$priv_list['page-vpn-vpnl2tp-users']['descr'] = gettext("Allow access to the 'VPN: VPN L2TP : Users' page.");
+$priv_list['page-vpn-vpnl2tp-users']['match'] = array();
+$priv_list['page-vpn-vpnl2tp-users']['match'][] = "vpn_l2tp_users.php*";
+
+$priv_list['page-vpn-vpnl2tp-users-edit'] = array();
+$priv_list['page-vpn-vpnl2tp-users-edit']['name'] = gettext("WebCfg - VPN: VPN L2TP : Users : Edit page");
+$priv_list['page-vpn-vpnl2tp-users-edit']['descr'] = gettext("Allow access to the 'VPN: VPN L2TP : Users : Edit' page.");
+$priv_list['page-vpn-vpnl2tp-users-edit']['match'] = array();
+$priv_list['page-vpn-vpnl2tp-users-edit']['match'][] = "vpn_l2tp_users_edit.php*";
+
+$priv_list['page-openvpn-client'] = array();
+$priv_list['page-openvpn-client']['name'] = gettext("WebCfg - OpenVPN: Client page");
+$priv_list['page-openvpn-client']['descr'] = gettext("Allow access to the 'OpenVPN: Client' page.");
+$priv_list['page-openvpn-client']['match'] = array();
+$priv_list['page-openvpn-client']['match'][] = "vpn_openvpn_client.php*";
+
+$priv_list['page-openvpn-csc'] = array();
+$priv_list['page-openvpn-csc']['name'] = gettext("WebCfg - OpenVPN: Client Specific Override page");
+$priv_list['page-openvpn-csc']['descr'] = gettext("Allow access to the 'OpenVPN: Client Specific Override' page.");
+$priv_list['page-openvpn-csc']['match'] = array();
+$priv_list['page-openvpn-csc']['match'][] = "vpn_openvpn_csc.php*";
+
+$priv_list['page-openvpn-server'] = array();
+$priv_list['page-openvpn-server']['name'] = gettext("WebCfg - OpenVPN: Server page");
+$priv_list['page-openvpn-server']['descr'] = gettext("Allow access to the 'OpenVPN: Server' page.");
+$priv_list['page-openvpn-server']['match'] = array();
+$priv_list['page-openvpn-server']['match'][] = "vpn_openvpn_server.php*";
+
+$priv_list['page-services-pppoeserver'] = array();
+$priv_list['page-services-pppoeserver']['name'] = gettext("WebCfg - Services: PPPoE Server page");
+$priv_list['page-services-pppoeserver']['descr'] = gettext("Allow access to the 'Services: PPPoE Server' page.");
+$priv_list['page-services-pppoeserver']['match'] = array();
+$priv_list['page-services-pppoeserver']['match'][] = "vpn_pppoe.php*";
+
+$priv_list['page-services-pppoeserver-edit'] = array();
+$priv_list['page-services-pppoeserver-edit']['name'] = gettext("WebCfg - Services: PPPoE Server: Edit page");
+$priv_list['page-services-pppoeserver-edit']['descr'] = gettext("Allow access to the 'Services: PPPoE Server: Edit' page.");
+$priv_list['page-services-pppoeserver-edit']['match'] = array();
+$priv_list['page-services-pppoeserver-edit']['match'][] = "vpn_pppoe_edit.php*";
+
+$priv_list['page-vpn-vpnpptp'] = array();
+$priv_list['page-vpn-vpnpptp']['name'] = gettext("WebCfg - VPN: VPN PPTP page");
+$priv_list['page-vpn-vpnpptp']['descr'] = gettext("Allow access to the 'VPN: VPN PPTP' page.");
+$priv_list['page-vpn-vpnpptp']['match'] = array();
+$priv_list['page-vpn-vpnpptp']['match'][] = "vpn_pptp.php*";
+
+$priv_list['page-vpn-vpnpptp-users'] = array();
+$priv_list['page-vpn-vpnpptp-users']['name'] = gettext("WebCfg - VPN: VPN PPTP: Users page");
+$priv_list['page-vpn-vpnpptp-users']['descr'] = gettext("Allow access to the 'VPN: VPN PPTP: Users' page.");
+$priv_list['page-vpn-vpnpptp-users']['match'] = array();
+$priv_list['page-vpn-vpnpptp-users']['match'][] = "vpn_pptp_users.php*";
+
+$priv_list['page-vpn-vpnpptp-user-edit'] = array();
+$priv_list['page-vpn-vpnpptp-user-edit']['name'] = gettext("WebCfg - VPN: VPN PPTP: User: Edit page");
+$priv_list['page-vpn-vpnpptp-user-edit']['descr'] = gettext("Allow access to the 'VPN: VPN PPTP: User: Edit' page.");
+$priv_list['page-vpn-vpnpptp-user-edit']['match'] = array();
+$priv_list['page-vpn-vpnpptp-user-edit']['match'][] = "vpn_pptp_users_edit.php*";
+
+$priv_list['page-pfsensewizardsubsystem'] = array();
+$priv_list['page-pfsensewizardsubsystem']['name'] = gettext("WebCfg - pfSense wizard subsystem page");
+$priv_list['page-pfsensewizardsubsystem']['descr'] = gettext("Allow access to the 'pfSense wizard subsystem' page.");
+$priv_list['page-pfsensewizardsubsystem']['match'] = array();
+$priv_list['page-pfsensewizardsubsystem']['match'][] = "wizard.php*";
+
+$priv_list['page-xmlrpclibrary'] = array();
+$priv_list['page-xmlrpclibrary']['name'] = gettext("WebCfg - XMLRPC Library page");
+$priv_list['page-xmlrpclibrary']['descr'] = gettext("Allow access to the 'XMLRPC Library' page.");
+$priv_list['page-xmlrpclibrary']['match'] = array();
+$priv_list['page-xmlrpclibrary']['match'][] = "xmlrpc.php*";
+
+$priv_list['page-firewall-easyrule'] = array();
+$priv_list['page-firewall-easyrule']['name'] = gettext("WebCfg - Firewall: Easy Rule add/status page");
+$priv_list['page-firewall-easyrule']['descr'] = gettext("Allow access to the 'Firewall: Easy Rule' add/status page.");
+$priv_list['page-firewall-easyrule']['match'] = array();
+$priv_list['page-firewall-easyrule']['match'][] = "easyrule.php*";
+
+$priv_rmvd = array();
+
+?>
diff --git a/src/etc/inc/priv.inc b/src/etc/inc/priv.inc
new file mode 100644
index 0000000..851643b
--- /dev/null
+++ b/src/etc/inc/priv.inc
@@ -0,0 +1,337 @@
+<?php
+/* $Id$ */
+/*
+ priv.inc
+ Copyright (C) 2008 Shrew Soft Inc
+ All rights reserved.
+
+ Copyright (C) 2007, 2008 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2005-2006 Bill Marquette <bill.marquette@gmail.com>
+ All rights reserved.
+
+ Copyright (C) 2006 Paul Taylor <paultaylor@winn-dixie.com>.
+ All rights reserved.
+
+ Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+ pfSense_MODULE: auth
+*/
+
+require_once("priv.defs.inc");
+
+/* Load and process custom privs. */
+function get_priv_files($directory) {
+ $dir_array = array();
+ if (!is_dir($directory)) {
+ return;
+ }
+ if ($dh = opendir($directory)) {
+ while (($file = readdir($dh)) !== false) {
+ $canadd = 0;
+ if ($file == ".") {
+ $canadd = 1;
+ }
+ if ($file == "..") {
+ $canadd = 1;
+ }
+ if ($canadd == 0) {
+ array_push($dir_array, $file);
+ }
+ }
+ closedir($dh);
+ }
+ if (!is_array($dir_array)) {
+ return;
+ }
+ return $dir_array;
+}
+
+// Load and sort privs
+$dir_array = get_priv_files("/etc/inc/priv");
+foreach ($dir_array as $file) {
+ if (!is_dir("/etc/inc/priv/{$file}") && stristr($file, ".inc")) {
+ include("/etc/inc/priv/{$file}");
+ }
+}
+if (is_dir("/usr/local/pkg/priv")) {
+ $dir_array = get_priv_files("/usr/local/pkg/priv");
+ foreach ($dir_array as $file) {
+ if (!is_dir("/usr/local/pkg/priv/{$file}") && stristr($file, ".inc")) {
+ include("/usr/local/pkg/priv/{$file}");
+ }
+ }
+}
+
+if (is_array($priv_list)) {
+ sort_privs($priv_list);
+}
+
+function cmp_privkeys($a, $b) {
+ /* user privs at the top */
+ $auser = strncmp("user-", $a, 5);
+ $buser = strncmp("user-", $b, 5);
+ if ($auser != $buser) {
+ return $auser - $buser;
+ }
+
+ /* name compare others */
+ return strcasecmp($a, $b);
+}
+
+function sort_privs(& $privs) {
+ uksort($privs, "cmp_privkeys");
+}
+
+function cmp_page_matches($page, & $matches, $fullwc = true) {
+
+// $dbg_matches = implode(",", $matches);
+// log_error("debug: checking page {$page} match with {$dbg_matches}");
+
+ if (!is_array($matches)) {
+ return false;
+ }
+
+ /* skip any leading fwdslash */
+ $test = strpos($page, "/");
+ if ($test !== false && $test == 0) {
+ $page = substr($page, 1);
+ }
+
+ /* look for a match */
+ foreach ($matches as $match) {
+
+ /* possibly ignore full wildcard match */
+ if (!$fullwc && !strcmp($match , "*")) {
+ continue;
+ }
+
+ /* compare exact or wildcard match */
+ $match = str_replace(array(".", "*", "?"), array("\.", ".*", "\?"), $match);
+ $result = preg_match("@^/{$match}$@", "/{$page}");
+
+ if ($result) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function map_page_privname($page) {
+ global $priv_list;
+
+ foreach ($priv_list as $pname => $pdata) {
+ if (strncmp($pname, "page-", 5)) {
+ continue;
+ }
+ $fullwc = false;
+ if (!strcasecmp($page, "any")||!strcmp($page, "*")) {
+ $fullwc = true;
+ }
+ if (cmp_page_matches($page, $pdata['match'], $fullwc)) {
+ return $pname;
+ }
+ }
+
+ return false;
+}
+
+function get_user_privdesc(& $user) {
+ global $priv_list;
+
+ $privs = array();
+
+ $user_privs = $user['priv'];
+ if (!is_array($user_privs)) {
+ $user_privs = array();
+ }
+
+ $names = local_user_get_groups($user, true);
+
+ foreach ($names as $name) {
+ $group = getGroupEntry($name);
+ $group_privs = $group['priv'];
+ if (!is_array($group_privs)) {
+ continue;
+ }
+ foreach ($group_privs as $pname) {
+ if (in_array($pname, $user_privs)) {
+ continue;
+ }
+ if (!$priv_list[$pname]) {
+ continue;
+ }
+ $priv = $priv_list[$pname];
+ $priv['group'] = $group['name'];
+ $privs[] = $priv;
+ }
+ }
+
+ foreach ($user_privs as $pname) {
+ if ($priv_list[$pname]) {
+ $privs[] = $priv_list[$pname];
+ }
+ }
+
+ return $privs;
+}
+
+function isAllowed($username, $page) {
+ global $_SESSION;
+
+ if (!isset($username)) {
+ return false;
+ }
+
+ /* admin/root access check */
+ $user = getUserEntry($username);
+ if (isset($user)) {
+ if (isset($user['uid'])) {
+ if ($user['uid'] == 0) {
+ return true;
+ }
+ }
+ }
+
+ /* user privilege access check */
+ if (cmp_page_matches($page, $_SESSION['page-match'])) {
+ return true;
+ }
+
+ return false;
+}
+
+
+function isAllowedPage($page) {
+ global $_SESSION;
+
+
+ $username = $_SESSION['Username'];
+
+ if (!isset($username)) {
+ return false;
+ }
+
+ /* admin/root access check */
+ $user = getUserEntry($username);
+ if (isset($user)) {
+ if (isset($user['uid'])) {
+ if ($user['uid'] == 0) {
+ return true;
+ }
+ }
+ }
+
+ /* user privilege access check */
+ return cmp_page_matches($page, $_SESSION['page-match']);
+}
+
+function getPrivPages(& $entry, & $allowed_pages) {
+ global $priv_list;
+
+ if (!is_array($entry['priv'])) {
+ return;
+ }
+
+ foreach ($entry['priv'] as $pname) {
+ if (strncmp($pname, "page-", 5)) {
+ continue;
+ }
+ $priv = &$priv_list[$pname];
+ if (!is_array($priv)) {
+ continue;
+ }
+ $matches = &$priv['match'];
+ if (!is_array($matches)) {
+ continue;
+ }
+ foreach ($matches as $match) {
+ $allowed_pages[] = $match;
+ }
+ }
+}
+
+function getAllowedPages($username, &$attributes = array()) {
+ global $config, $_SESSION;
+
+ if (!function_exists("ldap_connect")) {
+ return;
+ }
+
+ $allowed_pages = array();
+ $allowed_groups = array();
+
+ $authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
+ // obtain ldap groups if we are in ldap mode
+ if ($authcfg['type'] == "ldap") {
+ $allowed_groups = @ldap_get_groups($username, $authcfg);
+ } elseif ($authcfg['type'] == "radius") {
+ $allowed_groups = @radius_get_groups($attributes);
+ }
+ if (!$allowed_groups) {
+ // search for a local user by name
+ $local_user = getUserEntry($username);
+
+ // obtain local user pages and groups if we have a local user
+ if ($local_user) {
+ getPrivPages($local_user, $allowed_pages);
+ $allowed_groups = local_user_get_groups($local_user);
+ }
+ }
+
+ // build a list of allowed pages
+ if (is_array($config['system']['group']) && is_array($allowed_groups)) {
+ foreach ($config['system']['group'] as $group) {
+ if (in_array($group['name'], $allowed_groups)) {
+ getPrivPages($group, $allowed_pages);
+ }
+ }
+ }
+
+// $dbg_pages = implode(",", $allowed_pages);
+// $dbg_groups = implode(",", $allowed_groups);
+// log_error("debug: user {$username} groups = {$dbg_groups}");
+// log_error("debug: user {$username} pages = {$dbg_pages}");
+
+ $_SESSION['page-match'] = $allowed_pages;
+
+ return $allowed_pages;
+}
+
+function sort_user_privs($privs) {
+ // Privileges to place first, to redirect properly.
+ $priority_privs = array("page-dashboard-all", "page-system-login/logout");
+
+ $fprivs = array_intersect($privs, $priority_privs);
+ $sprivs = array_diff($privs, $priority_privs);
+
+ return array_merge($fprivs, $sprivs);
+}
+?>
diff --git a/src/etc/inc/priv/user.priv.inc b/src/etc/inc/priv/user.priv.inc
new file mode 100644
index 0000000..6414008
--- /dev/null
+++ b/src/etc/inc/priv/user.priv.inc
@@ -0,0 +1,74 @@
+<?php
+
+global $priv_list;
+
+$priv_list['user-services-captiveportal-login'] = array();
+$priv_list['user-services-captiveportal-login']['name'] = gettext("User - Services - Captive portal login");
+$priv_list['user-services-captiveportal-login']['descr'] = gettext("Indicates whether the user is able to login on the captive portal.");
+
+$priv_list['page-help-all'] = array();
+$priv_list['page-help-all']['name'] = "WebCfg - Help pages";
+$priv_list['page-help-all']['descr'] = "Show all items on help menu";
+$priv_list['page-help-all']['match'] = array();
+$priv_list['page-help-all']['match'][] = "*help.php";
+
+$priv_list['page-dashboard-all'] = array();
+$priv_list['page-dashboard-all']['name'] = "WebCfg - Dashboard (all)";
+$priv_list['page-dashboard-all']['descr'] = "Allow access to all pages required for the dashboard.";
+$priv_list['page-dashboard-all']['match'] = array();
+$priv_list['page-dashboard-all']['match'][] = "index.php*";
+$priv_list['page-dashboard-all']['match'][] = "*.widget.php*";
+$priv_list['page-dashboard-all']['match'][] = "graph.php*";
+$priv_list['page-dashboard-all']['match'][] = "graph_cpu.php*";
+$priv_list['page-dashboard-all']['match'][] = "getstats.php*";
+$priv_list['page-dashboard-all']['match'][] = "ifstats.php*";
+$priv_list['page-dashboard-all']['match'][] = "diag_logs_filter_dynamic.php*";
+
+$priv_list['page-dashboard-widgets'] = array();
+$priv_list['page-dashboard-widgets']['name'] = "WebCfg - Dashboard widgets (direct access).";
+$priv_list['page-dashboard-widgets']['descr'] = "Allow direct access to all Dashboard widget pages, required for some widgets using AJAX.";
+$priv_list['page-dashboard-widgets']['match'] = array();
+$priv_list['page-dashboard-widgets']['match'][] = "*.widget.php*";
+
+$priv_list['user-config-readonly'] = array();
+$priv_list['user-config-readonly']['name'] = "User - Config - Deny Config Write";
+$priv_list['user-config-readonly']['descr'] = "If present, ignores requests from this user to write config.xml.";
+
+$priv_list['user-shell-access'] = array();
+$priv_list['user-shell-access']['name'] = "User - System - Shell account access";
+$priv_list['user-shell-access']['descr'] = "Indicates whether the user is able to login for ".
+ "example via SSH.";
+
+$priv_list['user-copy-files'] = array();
+$priv_list['user-copy-files']['name'] = "User - System - Copy files";
+$priv_list['user-copy-files']['descr'] = "Indicates whether the user is allowed to copy files ".
+ "onto the {$g['product_name']} appliance via SCP/SFTP. ".
+ "If you are going to use this privilege, you must install ".
+ "scponly on the appliance (Hint: pkg_add -r scponly).";
+
+$priv_list['user-ssh-tunnel'] = array();
+$priv_list['user-ssh-tunnel']['name'] = "User - System - SSH tunneling";
+$priv_list['user-ssh-tunnel']['descr'] = "Indicates whether the user is able to login for ".
+ "tunneling via SSH when they have no shell access. ".
+ "Note: User - System - Copy files conflicts with ".
+ "this privilege.";
+
+$priv_list['user-ipsec-xauth-dialin'] = array();
+$priv_list['user-ipsec-xauth-dialin']['name'] = "User - VPN - IPsec xauth Dialin";
+$priv_list['user-ipsec-xauth-dialin']['descr'] = "Indicates whether the user is allowed to dial in via IPsec xauth ".
+ "(Note: Does not allow shell access, but may allow ".
+ "the user to create SSH tunnels)";
+
+$priv_list['user-l2tp-dialin'] = array();
+$priv_list['user-l2tp-dialin']['name'] = "User - VPN - L2TP Dialin";
+$priv_list['user-l2tp-dialin']['descr'] = "Indicates whether the user is allowed to dial in via L2TP";
+
+$priv_list['user-pptp-dialin'] = array();
+$priv_list['user-pptp-dialin']['name'] = "User - VPN - PPTP Dialin";
+$priv_list['user-pptp-dialin']['descr'] = "Indicates whether the user is allowed to dial in via PPTP";
+
+$priv_list['user-pppoe-dialin'] = array();
+$priv_list['user-pppoe-dialin']['name'] = "User - VPN - PPPOE Dialin";
+$priv_list['user-pppoe-dialin']['descr'] = "Indicates whether the user is allowed to dial in via PPPOE";
+
+?>
diff --git a/src/etc/inc/r53.class b/src/etc/inc/r53.class
new file mode 100644
index 0000000..89faa26
--- /dev/null
+++ b/src/etc/inc/r53.class
@@ -0,0 +1,754 @@
+<?php
+/**
+*
+* Copyright (c) 2011, Dan Myers.
+* Parts copyright (c) 2008, Donovan Schonknecht.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* - Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* - Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* This is a modified BSD license (the third clause has been removed).
+* The BSD license may be found here:
+* http://www.opensource.org/licenses/bsd-license.php
+*
+* Amazon Route 53 is a trademark of Amazon.com, Inc. or its affiliates.
+*
+* Route53 is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
+* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
+*
+*/
+
+/**
+* Amazon Route53 PHP class
+*
+* @link http://sourceforge.net/projects/php-r53/
+* version 0.9.0
+*
+*/
+class Route53
+{
+ const API_VERSION = '2010-10-01';
+
+ protected $__accessKey; // AWS Access key
+ protected $__secretKey; // AWS Secret key
+ protected $__host;
+
+ public function getAccessKey() { return $this->__accessKey; }
+ public function getSecretKey() { return $this->__secretKey; }
+ public function getHost() { return $this->__host; }
+
+ protected $__verifyHost = 1;
+ protected $__verifyPeer = 1;
+
+ // verifyHost and verifyPeer determine whether curl verifies ssl certificates.
+ // It may be necessary to disable these checks on certain systems.
+ // These only have an effect if SSL is enabled.
+ public function verifyHost() { return $this->__verifyHost; }
+ public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
+
+ public function verifyPeer() { return $this->__verifyPeer; }
+ public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
+
+ /**
+ * Constructor
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function __construct($accessKey = null, $secretKey = null, $host = 'route53.amazonaws.com') {
+ if ($accessKey !== null && $secretKey !== null) {
+ $this->setAuth($accessKey, $secretKey);
+ }
+ $this->__host = $host;
+ }
+
+ /**
+ * Set AWS access key and secret key
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function setAuth($accessKey, $secretKey) {
+ $this->__accessKey = $accessKey;
+ $this->__secretKey = $secretKey;
+ }
+
+ /**
+ * Lists the hosted zones on the account
+ *
+ * @param string marker A pagination marker returned by a previous truncated call
+ * @param int maxItems The maximum number of items per page. The service uses min($maxItems, 100).
+ * @return A list of hosted zones
+ */
+ public function listHostedZones($marker = null, $maxItems = 100) {
+ $rest = new Route53Request($this, 'hostedzone', 'GET');
+
+ if($marker !== null) {
+ $rest->setParameter('marker', $marker);
+ }
+ if($maxItems !== 100) {
+ $rest->setParameter('maxitems', $maxItems);
+ }
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('listHostedZones', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body))
+ {
+ return $response;
+ }
+
+ $zones = array();
+ foreach($rest->body->HostedZones->HostedZone as $z)
+ {
+ $zones[] = $this->parseHostedZone($z);
+ }
+ $response['HostedZone'] = $zones;
+
+ if(isset($rest->body->MaxItems)) {
+ $response['MaxItems'] = (string)$rest->body->MaxItems;
+ }
+
+ if(isset($rest->body->IsTruncated)) {
+ $response['IsTruncated'] = (string)$rest->body->IsTruncated;
+ if($response['IsTruncated'] == 'true') {
+ $response['NextMarker'] = (string)$rest->body->NextMarker;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Retrieves information on a specified hosted zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @return A data structure containing information about the specified zone
+ */
+ public function getHostedZone($zoneId) {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId, 'GET');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getHostedZone', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body))
+ {
+ return $response;
+ }
+
+ $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
+ $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
+
+ return $response;
+ }
+
+ /**
+ * Creates a new hosted zone
+ *
+ * @param string name The name of the hosted zone (e.g. "example.com.")
+ * @param string reference A user-specified unique reference for this request
+ * @param string comment An optional user-specified comment to attach to the zone
+ * @return A data structure containing information about the newly created zone
+ */
+ public function createHostedZone($name, $reference, $comment = '') {
+ // hosted zone names must end with a period, but people will forget this a lot...
+ if(strrpos($name, '.') != (strlen($name) - 1)) {
+ $name .= '.';
+ }
+
+ $data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ $data .= '<CreateHostedZoneRequest xmlns="https://route53.amazonaws.com/doc/'.Route53::API_VERSION."/\">\n";
+ $data .= '<Name>'.$name."</Name>\n";
+ $data .= '<CallerReference>'.$reference."</CallerReference>\n";
+ if(strlen($comment) > 0) {
+ $data .= "<HostedZoneConfig>\n";
+ $data .= '<Comment>'.$comment."</Comment>\n";
+ $data .= "</HostedZoneConfig>\n";
+ }
+ $data .= "</CreateHostedZoneRequest>\n";
+
+ $rest = new Route53Request($this, 'hostedzone', 'POST', $data);
+
+ $rest = $rest->getResponse();
+
+ if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204)) ) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('createHostedZone', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body))
+ {
+ return $response;
+ }
+
+ $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
+ $response['ChangeInfo'] = $this->parseChangeInfo($rest->body->ChangeInfo);
+ $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
+
+ return $response;
+ }
+
+ /**
+ * Retrieves information on a specified hosted zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @return The change request data corresponding to this delete
+ */
+ public function deleteHostedZone($zoneId) {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId, 'DELETE');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('deleteHostedZone', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body))
+ {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+ /**
+ * Retrieves a list of resource record sets for a given zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @param string type The type of resource record set to begin listing from. If this is specified, $name must also be specified.
+ * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
+ * @param string name The name at which to begin listing resource records (in the lexographic order of records).
+ * @param int maxItems The maximum number of results to return. The service uses min($maxItems, 100).
+ * @return The list of matching resource record sets
+ */
+ public function listResourceRecordSets($zoneId, $type = '', $name = '', $maxItems = 100) {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId.'/rrset', 'GET');
+
+ if(strlen($type) > 0) {
+ $rest->setParameter('type', $type);
+ }
+ if(strlen($name) > 0) {
+ $rest->setParameter('name', $name);
+ }
+ if($maxItems != 100) {
+ $rest->setParameter('maxitems', $maxItems);
+ }
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('listResourceRecordSets', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body))
+ {
+ return $response;
+ }
+
+ $recordSets = array();
+ foreach($rest->body->ResourceRecordSets->ResourceRecordSet as $set) {
+ $recordSets[] = $this->parseResourceRecordSet($set);
+ }
+
+ $response['ResourceRecordSets'] = $recordSets;
+
+ if(isset($rest->body->MaxItems)) {
+ $response['MaxItems'] = (string)$rest->body->MaxItems;
+ }
+
+ if(isset($rest->body->IsTruncated)) {
+ $response['IsTruncated'] = (string)$rest->body->IsTruncated;
+ if($response['IsTruncated'] == 'true') {
+ $response['NextRecordName'] = (string)$rest->body->NextRecordName;
+ $response['NextRecordType'] = (string)$rest->body->NextRecordType;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Makes the specified resource record set changes (create or delete).
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @param array changes An array of change objects, as they are returned by the prepareChange utility method.
+ * You may also pass a single change object.
+ * @param string comment An optional comment to attach to the change request
+ * @return The status of the change request
+ */
+ public function changeResourceRecordSets($zoneId, $changes, $comment = '') {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ $data .= '<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/'.Route53::API_VERSION."/\">\n";
+ $data .= "<ChangeBatch>\n";
+
+ if(strlen($comment) > 0) {
+ $data .= '<Comment>'.$comment."</Comment>\n";
+ }
+
+ if(!is_array($changes)) {
+ $changes = array($changes);
+ }
+
+ $data .= "<Changes>\n";
+ foreach($changes as $change) {
+ $data .= $change;
+ }
+ $data .= "</Changes>\n";
+
+ $data .= "</ChangeBatch>\n";
+ $data .= "</ChangeResourceRecordSetsRequest>\n";
+
+ $rest = new Route53Request($this, $zoneId.'/rrset', 'POST', $data);
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204))) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('changeResourceRecordSets', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body))
+ {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+ /**
+ * Retrieves information on a specified change request
+ *
+ * @param string changeId The id of the change, as returned by CreateHostedZoneResponse or ChangeResourceRecordSets
+ * In other words, if CreateHostedZoneResponse showed the change's Id as '/change/C2682N5HXP0BZ4',
+ * then that full value should be passed here, including the '/change/' prefix.
+ * @return The status of the change request
+ */
+ public function getChange($changeId) {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($changeId, '/');
+
+ $rest = new Route53Request($this, $changeId, 'GET');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getChange', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body))
+ {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+
+
+ /**
+ * Utility function to parse a HostedZone tag structure
+ */
+ private function parseHostedZone($tag) {
+ $zone = array();
+ $zone['Id'] = (string)$tag->Id;
+ $zone['Name'] = (string)$tag->Name;
+ $zone['CallerReference'] = (string)$tag->CallerReference;
+
+ // these might always be set, but check just in case, since
+ // their values are option on CreateHostedZone requests
+ if(isset($tag->Config) && isset($tag->Config->Comment)) {
+ $zone['Config'] = array('Comment' => (string)$tag->Config->Comment);
+ }
+
+ return $zone;
+ }
+
+ /**
+ * Utility function to parse a ChangeInfo tag structure
+ */
+ private function parseChangeInfo($tag) {
+ $info = array();
+ $info['Id'] = (string)$tag->Id;
+ $info['Status'] = (string)$tag->Status;
+ $info['SubmittedAt'] = (string)$tag->SubmittedAt;
+ return $info;
+ }
+
+ /**
+ * Utility function to parse a DelegationSet tag structure
+ */
+ private function parseDelegationSet($tag) {
+ $servers = array();
+ foreach($tag->NameServers->NameServer as $ns) {
+ $servers[] = (string)$ns;
+ }
+ return $servers;
+ }
+
+ /**
+ * Utility function to parse a ResourceRecordSet tag structure
+ */
+ private function parseResourceRecordSet($tag) {
+ $rrs = array();
+ $rrs['Name'] = (string)$tag->Name;
+ $rrs['Type'] = (string)$tag->Type;
+ $rrs['TTL'] = (string)$tag->TTL;
+ $rrs['ResourceRecords'] = array();
+ foreach($tag->ResourceRecords->ResourceRecord as $rr) {
+ $rrs['ResourceRecords'][] = (string)$rr->Value;
+ }
+ return $rrs;
+ }
+
+ /**
+ * Utility function to prepare a Change object for ChangeResourceRecordSets requests.
+ * All fields are required.
+ *
+ * @param string action The action to perform. One of: CREATE, DELETE
+ * @param string name The name to perform the action on.
+ * If it does not end with '.', then AWS treats the name as relative to the zone root.
+ * @param string type The type of record being modified.
+ * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
+ * @param int ttl The time-to-live value for this record, in seconds.
+ * @param array records An array of resource records to attach to this change.
+ * Each member of this array can either be a string, or an array of strings.
+ * Passing an array of strings will attach multiple values to a single resource record.
+ * If a single string is passed as $records instead of an array,
+ * it will be treated as a single-member array.
+ * @return object An opaque object containing the change request.
+ * Do not write code that depends on the contents of this object, as it may change at any time.
+ */
+ public function prepareChange($action, $name, $type, $ttl, $records) {
+ $change = "<Change>\n";
+ $change .= '<Action>'.$action."</Action>\n";
+ $change .= "<ResourceRecordSet>\n";
+ $change .= '<Name>'.$name."</Name>\n";
+ $change .= '<Type>'.$type."</Type>\n";
+ $change .= '<TTL>'.$ttl."</TTL>\n";
+ $change .= "<ResourceRecords>\n";
+
+ if(!is_array($records)) {
+ $records = array($records);
+ }
+
+ foreach($records as $record) {
+ $change .= "<ResourceRecord>\n";
+ if(is_array($record)) {
+ foreach($record as $value) {
+ $change .= '<Value>'.$value."</Value>\n";
+ }
+ }
+ else {
+ $change .= '<Value>'.$record."</Value>\n";
+ }
+ $change .= "</ResourceRecord>\n";
+ }
+
+ $change .= "</ResourceRecords>\n";
+ $change .= "</ResourceRecordSet>\n";
+ $change .= "</Change>\n";
+
+ return $change;
+ }
+
+ /**
+ * Trigger an error message
+ *
+ * @internal Used by member functions to output errors
+ * @param array $error Array containing error information
+ * @return string
+ */
+ public function __triggerError($functionname, $error)
+ {
+ if($error == false) {
+ trigger_error(sprintf("Route53::%s(): Encountered an error, but no description given", $functionname), E_USER_WARNING);
+ }
+ else if(isset($error['curl']) && $error['curl'])
+ {
+ trigger_error(sprintf("Route53::%s(): %s %s", $functionname, $error['code'], $error['message']), E_USER_WARNING);
+ }
+ else if(isset($error['Error']))
+ {
+ $e = $error['Error'];
+ $message = sprintf("Route53::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
+ trigger_error($message, E_USER_WARNING);
+ }
+ }
+
+ /**
+ * Callback handler for 503 retries.
+ *
+ * @internal Used by SimpleDBRequest to call the user-specified callback, if set
+ * @param $attempt The number of failed attempts so far
+ * @return The retry delay in microseconds, or 0 to stop retrying.
+ */
+ public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
+ {
+ if(is_callable($this->__serviceUnavailableRetryDelayCallback)) {
+ $callback = $this->__serviceUnavailableRetryDelayCallback;
+ return $callback($attempt);
+ }
+ return 0;
+ }
+}
+
+final class Route53Request
+{
+ private $r53, $action, $verb, $data, $parameters = array();
+ public $response;
+
+ /**
+ * Constructor
+ *
+ * @param string $r53 The Route53 object making this request
+ * @param string $action SimpleDB action
+ * @param string $verb HTTP verb
+ * @param string $data For POST requests, the data being posted (optional)
+ * @return mixed
+ */
+ function __construct($r53, $action, $verb, $data = '') {
+ $this->r53 = $r53;
+ $this->action = $action;
+ $this->verb = $verb;
+ $this->data = $data;
+ $this->response = new STDClass;
+ $this->response->error = false;
+ }
+
+ /**
+ * Set request parameter
+ *
+ * @param string $key Key
+ * @param string $value Value
+ * @param boolean $replace Whether to replace the key if it already exists (default true)
+ * @return void
+ */
+ public function setParameter($key, $value, $replace = true) {
+ if(!$replace && isset($this->parameters[$key]))
+ {
+ $temp = (array)($this->parameters[$key]);
+ $temp[] = $value;
+ $this->parameters[$key] = $temp;
+ }
+ else
+ {
+ $this->parameters[$key] = $value;
+ }
+ }
+
+ /**
+ * Get the response
+ *
+ * @return object | false
+ */
+ public function getResponse() {
+
+ $params = array();
+ foreach ($this->parameters as $var => $value)
+ {
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ {
+ $params[] = $var.'='.$this->__customUrlEncode($v);
+ }
+ }
+ else
+ {
+ $params[] = $var.'='.$this->__customUrlEncode($value);
+ }
+ }
+
+ sort($params, SORT_STRING);
+
+ $query = implode('&', $params);
+
+ // must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
+ $date = gmdate('D, d M Y H:i:s e');
+
+ $headers = array();
+ $headers[] = 'Date: '.$date;
+ $headers[] = 'Host: '.$this->r53->getHost();
+
+ $auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->r53->getAccessKey();
+ $auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
+ $headers[] = 'X-Amzn-Authorization: '.$auth;
+
+ $url = 'https://'.$this->r53->getHost().'/'.Route53::API_VERSION.'/'.$this->action.'?'.$query;
+
+ // Basic setup
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_USERAGENT, 'Route53/php');
+
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->r53->verifyHost() ? 1 : 0));
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->r53->verifyPeer() ? 1 : 0));
+
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+
+ // Request types
+ switch ($this->verb) {
+ case 'GET': break;
+ case 'POST':
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
+ if(strlen($this->data) > 0) {
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
+ $headers[] = 'Content-Type: text/plain';
+ $headers[] = 'Content-Length: '.strlen($this->data);
+ }
+ break;
+ case 'DELETE':
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
+ break;
+ default: break;
+ }
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+
+ // Execute, grab errors
+ if (curl_exec($curl)) {
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ } else {
+ $this->response->error = array(
+ 'curl' => true,
+ 'code' => curl_errno($curl),
+ 'message' => curl_error($curl),
+ 'resource' => $this->resource
+ );
+ }
+
+ @curl_close($curl);
+
+ // Parse body into XML
+ if ($this->response->error === false && isset($this->response->body)) {
+ $this->response->body = simplexml_load_string($this->response->body);
+
+ // Grab Route53 errors
+ if (!in_array($this->response->code, array(200, 201, 202, 204))
+ && isset($this->response->body->Error)) {
+ $error = $this->response->body->Error;
+ $output = array();
+ $output['curl'] = false;
+ $output['Error'] = array();
+ $output['Error']['Type'] = (string)$error->Type;
+ $output['Error']['Code'] = (string)$error->Code;
+ $output['Error']['Message'] = (string)$error->Message;
+ $output['RequestId'] = (string)$this->response->body->RequestId;
+
+ $this->response->error = $output;
+ unset($this->response->body);
+ }
+ }
+
+ return $this->response;
+ }
+
+ /**
+ * CURL write callback
+ *
+ * @param resource &$curl CURL resource
+ * @param string &$data Data
+ * @return integer
+ */
+ private function __responseWriteCallback(&$curl, &$data) {
+ $this->response->body .= $data;
+ return strlen($data);
+ }
+
+ /**
+ * Contributed by afx114
+ * URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
+ * PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
+ * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
+ *
+ * @param string $var String to encode
+ * @return string
+ */
+ private function __customUrlEncode($var) {
+ return str_replace('%7E', '~', rawurlencode($var));
+ }
+
+ /**
+ * Generate the auth string using Hmac-SHA256
+ *
+ * @internal Used by SimpleDBRequest::getResponse()
+ * @param string $string String to sign
+ * @return string
+ */
+ private function __getSignature($string) {
+ return base64_encode(hash_hmac('sha256', $string, $this->r53->getSecretKey(), true));
+ }
+}
diff --git a/src/etc/inc/radius.inc b/src/etc/inc/radius.inc
new file mode 100644
index 0000000..ac610bd
--- /dev/null
+++ b/src/etc/inc/radius.inc
@@ -0,0 +1,1208 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/*
+ radius.inc
+
+ Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This code cannot simply be copied and put under the GNU Public License or
+ any other GPL-like (LGPL, GPL2) License.
+
+ This version of RADIUS.php has been modified by
+ Jonathan De Graeve <m0n0wall@esstec.be> to integrate with M0n0wall <http://www.m0n0.ch/wall>
+
+ Changes made include:
+ * StandardAttributes for M0n0wall use
+ * Removed internal Session-Id creation
+ * Adding of ReplyMessage to getAttributes()
+ * Adding of listAttributes()
+ * Adding of VENDOR Bay Networks (Nortel)
+ * Adding of VENDOR Nomadix
+ * Adding of VENDOR WISPr (Wi-Fi Alliance)
+ * Adding of VENDOR ChilliSpot (bandwidth-attributes only)
+
+*/
+
+/*
+ pfSense_MODULE: auth
+*/
+
+require_once("PEAR.inc");
+require_once("radius_authentication.inc");
+require_once("radius_accounting.inc");
+
+/**
+* Client implementation of RADIUS. This are wrapper classes for
+* the RADIUS PECL
+* Provides RADIUS Authentication (RFC2865) and RADIUS Accounting (RFC2866).
+*
+* @package Auth_RADIUS
+* @author Michael Bretterklieber <michael@bretterklieber.com>
+* @access public
+* @version $Revision: 1.5 $
+*/
+
+PEAR::loadExtension('radius');
+
+/**
+ * class Auth_RADIUS
+ *
+ * Abstract base class for RADIUS
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS extends PEAR {
+
+ /**
+ * List of RADIUS servers.
+ * @var array
+ * @see addServer(), putServer()
+ */
+ var $_servers = array();
+
+ /**
+ * Path to the configuration-file.
+ * @var string
+ * @see setConfigFile()
+ */
+ var $_configfile = null;
+
+ /**
+ * Resource.
+ * @var resource
+ * @see open(), close()
+ */
+ var $res = null;
+
+ /**
+ * Username for authentication and accounting requests.
+ * @var string
+ */
+ var $username = null;
+
+ /**
+ * Password for plaintext-authentication (PAP).
+ * @var string
+ */
+ var $password = null;
+
+ /**
+ * List of known attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $attributes = array();
+
+ /**
+ * List of raw attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $rawAttributes = array();
+
+ /**
+ * List of raw vendor specific attributes.
+ * @var array
+ * @see dumpAttributes(), getAttributes()
+ */
+ var $rawVendorAttributes = array();
+
+ /**
+ * Constructor
+ *
+ * Loads the RADIUS PECL/extension
+ *
+ * @return void
+ */
+ function Auth_RADIUS()
+ {
+ $this->PEAR();
+ }
+
+ /**
+ * Adds a RADIUS server to the list of servers for requests.
+ *
+ * At most 10 servers may be specified. When multiple servers
+ * are given, they are tried in round-robin fashion until a
+ * valid response is received
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @param integer $port Portnumber
+ * @param string $sharedSecret Shared secret
+ * @param integer $timeout Timeout for each request
+ * @param integer $maxtries Max. retries for each request
+ * @return void
+ */
+ function addServer($servername = 'localhost', $port = 0, $sharedSecret = 'testing123', $timeout = 3, $maxtries = 2)
+ {
+ $this->_servers[] = array($servername, $port, $sharedSecret, $timeout, $maxtries);
+ }
+
+ /**
+ * Returns an error message, if an error occurred.
+ *
+ * @access public
+ * @return string
+ */
+ function getError()
+ {
+ return radius_strerror($this->res);
+ }
+
+ /**
+ * Sets the configuration-file.
+ *
+ * @access public
+ * @param string $file Path to the configuration file
+ * @return void
+ */
+ function setConfigfile($file)
+ {
+ $this->_configfile = $file;
+ }
+
+ /**
+ * Puts an attribute.
+ *
+ * @access public
+ * @param integer $attrib Attribute-number
+ * @param mixed $port Attribute-value
+ * @param type $type Attribute-type
+ * @return bool true on success, false on error
+ */
+ function putAttribute($attrib, $value, $type = null)
+ {
+ if ($type == null) {
+ $type = gettype($value);
+ }
+
+ switch ($type) {
+ case 'integer':
+ // Fix a conversion error so we should be able to handle 4GB values
+ return radius_put_int($this->res, $attrib, (float)$value);
+
+ case 'addr':
+ return radius_put_addr($this->res, $attrib, $value);
+
+ case 'string':
+ default:
+ return radius_put_attr($this->res, $attrib, $value);
+ }
+
+ }
+
+ /**
+ * Puts a vendor-specific attribute.
+ *
+ * @access public
+ * @param integer $vendor Vendor (MSoft, Cisco, ...)
+ * @param integer $attrib Attribute-number
+ * @param mixed $port Attribute-value
+ * @param type $type Attribute-type
+ * @return bool true on success, false on error
+ */
+ function putVendorAttribute($vendor, $attrib, $value, $type = null)
+ {
+
+ if ($type == null) {
+ $type = gettype($value);
+ }
+
+ switch ($type) {
+ case 'integer':
+ return radius_put_vendor_int($this->res, $vendor, $attrib, $value);
+
+ case 'addr':
+ return radius_put_vendor_addr($this->res, $vendor,$attrib, $value);
+
+ case 'string':
+ default:
+ return radius_put_vendor_attr($this->res, $vendor, $attrib, $value);
+ }
+
+ }
+
+ /**
+ * Prints known attributes received from the server.
+ *
+ * @access public
+ */
+ function dumpAttributes()
+ {
+ foreach ($this->attributes as $name => $data) {
+ echo "$name:$data<br />\n";
+ }
+ }
+
+ /**
+ * Return our know attributes array received from the server.
+ *
+ * @access public
+ */
+ function listAttributes()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * Overwrite this.
+ *
+ * @access public
+ */
+ function open()
+ {
+ }
+
+ /**
+ * Overwrite this.
+ *
+ * @access public
+ */
+ function createRequest()
+ {
+ }
+
+ /**
+ * Puts standard attributes.
+ *
+ * These attributes will always be present in a radius request
+ *
+ * @access public
+ */
+ function putStandardAttributes()
+ {
+ global $config, $cpzone;
+
+ if (!function_exists("getNasIp")) {
+ $ipaddr = "0.0.0.0";
+ } else {
+ $ipaddr = getNasIP();
+ }
+ // Add support for sending NAS-IP-Address, set this explicitly as an ip_addr
+ $this->putAttribute(RADIUS_NAS_IP_ADDRESS, $ipaddr, "addr");
+
+ // Add support for sending NAS-Identifier
+ if (empty($config["captiveportal"][$cpzone]["radiusnasid"])) {
+ $nasId = php_uname("n");
+ } else {
+ $nasId = $config["captiveportal"][$cpzone]["radiusnasid"];
+ }
+ $this->putAttribute(RADIUS_NAS_IDENTIFIER, $nasId);
+ }
+
+ /**
+ * Puts custom attributes.
+ *
+ * @access public
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ }
+
+ /**
+ * Configures the radius library.
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @param integer $port Portnumber
+ * @param string $sharedSecret Shared secret
+ * @param integer $timeout Timeout for each request
+ * @param integer $maxtries Max. retries for each request
+ * @return bool true on success, false on error
+ * @see addServer()
+ */
+ function putServer($servername, $port = 0, $sharedsecret = 'testing123', $timeout = 3, $maxtries = 3)
+ {
+ if (!radius_add_server($this->res, $servername, $port, $sharedsecret, $timeout, $maxtries)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Configures the radius library via external configurationfile
+ *
+ * @access public
+ * @param string $servername Servername or IP-Address
+ * @return bool true on success, false on error
+ */
+ function putConfigfile($file)
+ {
+ if (!radius_config($this->res, $file)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Initiates a RADIUS request.
+ *
+ * @access public
+ * @return bool true on success, false on errors
+ */
+ function start()
+ {
+ if (!$this->open()) {
+ return false;
+ }
+
+ foreach ($this->_servers as $s) {
+ // Servername, port, sharedsecret, timeout, retries
+ if (!$this->putServer($s[0], $s[1], $s[2], $s[3], $s[4])) {
+ return false;
+ }
+ }
+
+ if (!empty($this->_configfile)) {
+ if (!$this->putConfigfile($this->_configfile)) {
+ return false;
+ }
+ }
+
+ $this->createRequest();
+ $this->putStandardAttributes();
+ $this->putAuthAttributes();
+ return true;
+ }
+
+ /**
+ * Sends a prepared RADIUS request and waits for a response
+ *
+ * @access public
+ * @return mixed true on success, false on reject, PEAR_Error on error
+ */
+ function send()
+ {
+ $req = radius_send_request($this->res);
+ if (!$req) {
+ return $this->raiseError(gettext('Error sending request:') . ' ' . $this->getError());
+ }
+
+ switch($req) {
+ case RADIUS_ACCESS_ACCEPT:
+ if (is_subclass_of($this, 'auth_radius_acct')) {
+ return $this->raiseError(gettext('RADIUS_ACCESS_ACCEPT is unexpected for accounting'));
+ }
+ return true;
+
+ case RADIUS_ACCESS_REJECT:
+ return false;
+
+ case RADIUS_ACCOUNTING_RESPONSE:
+ if (is_subclass_of($this, 'auth_radius_pap')) {
+ return $this->raiseError(gettext('RADIUS_ACCOUNTING_RESPONSE is unexpected for authentication'));
+ }
+ return true;
+
+ default:
+ return $this->raiseError(sprintf(gettext("Unexpected return value: %s"),$req));
+ }
+
+ }
+
+ /**
+ * Reads all received attributes after sending the request.
+ *
+ * This methos stores know attributes in the property attributes,
+ * all attributes (including known attibutes) are stored in rawAttributes
+ * or rawVendorAttributes.
+ * NOTE: call this functio also even if the request was rejected, because the
+ * Server returns usualy an errormessage
+ *
+ * @access public
+ * @return bool true on success, false on error
+ */
+ function getAttributes()
+ {
+
+ while ($attrib = radius_get_attr($this->res)) {
+
+ if (!is_array($attrib)) {
+ return false;
+ }
+
+ $attr = $attrib['attr'];
+ $data = $attrib['data'];
+
+ $this->rawAttributes[$attr] = $data;
+
+ switch ($attr) {
+ case RADIUS_FRAMED_IP_ADDRESS:
+ $this->attributes['framed_ip'] = radius_cvt_addr($data);
+ break;
+
+ case RADIUS_FRAMED_IP_NETMASK:
+ $this->attributes['framed_mask'] = radius_cvt_addr($data);
+ break;
+
+ case RADIUS_FRAMED_MTU:
+ $this->attributes['framed_mtu'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FRAMED_COMPRESSION:
+ $this->attributes['framed_compression'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_SESSION_TIMEOUT:
+ $this->attributes['session_timeout'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_IDLE_TIMEOUT:
+ $this->attributes['idle_timeout'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_SERVICE_TYPE:
+ $this->attributes['service_type'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_CLASS:
+ $this->attributes['class'] = radius_cvt_string($data);
+ break;
+
+ case RADIUS_FRAMED_PROTOCOL:
+ $this->attributes['framed_protocol'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FRAMED_ROUTING:
+ $this->attributes['framed_routing'] = radius_cvt_int($data);
+ break;
+
+ case RADIUS_FILTER_ID:
+ $this->attributes['filter_id'] = radius_cvt_string($data);
+ break;
+
+ case RADIUS_REPLY_MESSAGE:
+ $this->attributes['reply_message'] = radius_cvt_string($data);
+ break;
+
+ case RADIUS_VENDOR_SPECIFIC:
+ $attribv = radius_get_vendor_attr($data);
+ if (!is_array($attribv)) {
+ return false;
+ }
+
+ $vendor = $attribv['vendor'];
+ $attrv = $attribv['attr'];
+ $datav = $attribv['data'];
+
+ $this->rawVendorAttributes[$vendor][$attrv] = $datav;
+
+ if ($vendor == RADIUS_VENDOR_MICROSOFT) {
+
+ switch ($attrv) {
+ case RADIUS_MICROSOFT_MS_CHAP2_SUCCESS:
+ $this->attributes['ms_chap2_success'] = radius_cvt_string($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_ERROR:
+ $this->attributes['ms_chap_error'] = radius_cvt_string(substr($datav,1));
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_DOMAIN:
+ $this->attributes['ms_chap_domain'] = radius_cvt_string($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
+ $this->attributes['ms_mppe_encryption_policy'] = radius_cvt_int($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
+ $this->attributes['ms_mppe_encryption_types'] = radius_cvt_int($datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_CHAP_MPPE_KEYS:
+ $demangled = radius_demangle($this->res, $datav);
+ $this->attributes['ms_chap_mppe_lm_key'] = substr($demangled, 0, 8);
+ $this->attributes['ms_chap_mppe_nt_key'] = substr($demangled, 8, RADIUS_MPPE_KEY_LEN);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_SEND_KEY:
+ $this->attributes['ms_chap_mppe_send_key'] = radius_demangle_mppe_key($this->res, $datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_MPPE_RECV_KEY:
+ $this->attributes['ms_chap_mppe_recv_key'] = radius_demangle_mppe_key($this->res, $datav);
+ break;
+
+ case RADIUS_MICROSOFT_MS_PRIMARY_DNS_SERVER:
+ $this->attributes['ms_primary_dns_server'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 1584) {
+
+ switch ($attrv) {
+ case 102:
+ $this->attributes['ces_group'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 3309) { /* RADIUS_VENDOR_NOMADIX */
+
+ switch ($attrv) {
+ case 1: /* RADIUS_NOMADIX_BW_UP */
+ $this->attributes['bw_up'] = radius_cvt_int($datav);
+ break;
+ case 2: /* RADIUS_NOMADIX_BW_DOWN */
+ $this->attributes['bw_down'] = radius_cvt_int($datav);
+ break;
+ case 3: /* RADIUS_NOMADIX_URL_REDIRECTION */
+ $this->attributes['url_redirection'] = radius_cvt_string($datav);
+ break;
+ case 5: /* RADIUS_NOMADIX_EXPIRATION */
+ $this->attributes['expiration'] = radius_cvt_string($datav);
+ break;
+ case 7: /* RADIUS_NOMADIX_MAXBYTESUP */
+ $this->attributes['maxbytesup'] = radius_cvt_int($datav);
+ break;
+ case 8: /* RADIUS_NOMADIX_MAXBYTESDOWN */
+ $this->attributes['maxbytesdown'] = radius_cvt_int($datav);
+ break;
+ case 10: /* RADIUS_NOMADIX_LOGOFF_URL */
+ $this->attributes['url_logoff'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 14122) { /* RADIUS_VENDOR_WISPr Wi-Fi Alliance */
+
+ switch ($attrv) {
+ case 1: /* WISPr-Location-ID */
+ $this->attributes['location_id'] = radius_cvt_string($datav);
+ break;
+ case 2: /* WISPr-Location-Name */
+ $this->attributes['location_name'] = radius_cvt_string($datav);
+ break;
+ case 3: /* WISPr-Logoff-URL */
+ $this->attributes['url_logoff'] = radius_cvt_string($datav);
+ break;
+ case 4: /* WISPr-Redirection-URL */
+ $this->attributes['url_redirection'] = radius_cvt_string($datav);
+ break;
+ case 5: /* WISPr-Bandwidth-Min-Up */
+ $this->attributes['bw_up_min'] = radius_cvt_int($datav);
+ break;
+ case 6: /* WISPr-Bandwidth-Min-Down */
+ $this->attributes['bw_down_min'] = radius_cvt_int($datav);
+ break;
+ case 7: /* WISPr-Bandwidth-Max-Up */
+ $this->attributes['bw_up'] = radius_cvt_int($datav);
+ break;
+ case 8: /* WISPr-Bandwidth-Max-Down */
+ $this->attributes['bw_down'] = radius_cvt_int($datav);
+ break;
+ case 9: /* WISPr-Session-Terminate-Time */
+ $this->attributes['session_terminate_time'] = radius_cvt_string($datav);
+ break;
+ case 10: /* WISPr-Session-Terminate-End-Of-Day */
+ $this->attributes['session_terminate_endofday'] = radius_cvt_int($datav);
+ break;
+ case 11: /* WISPr-Billing-Class-Of-Service */
+ $this->attributes['billing_class_of_service'] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 14559) { /* RADIUS_VENDOR_ChilliSpot */
+ switch ($attrv) {
+ case 4: /* ChilliSpot-Bandwidth-Max-Up */
+ $this->attributes['bw_up'] = radius_cvt_int($datav);
+ break;
+ case 5: /* ChilliSpot-Bandwidth-Max-Down */
+ $this->attributes['bw_down'] = radius_cvt_int($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 9) { /* RADIUS_VENDOR_CISCO */
+ switch ($attrv) {
+ case 1: /* Cisco-AVPair */
+ if (!is_array($this->attributes['ciscoavpair']))
+ $this->attributes['ciscoavpair'] = array();
+ $this->attributes['ciscoavpair'][] = radius_cvt_string($datav);
+ break;
+ }
+ }
+
+ elseif ($vendor == 8744) { /* Colubris / HP MSM wireless */
+ //documented at http://bizsupport1.austin.hp.com/bc/docs/support/SupportManual/c02704528/c02704528.pdf pg 15-67
+ if ($attrv == 0) { /* Colubris AV-Pair */
+ $datav = explode('=', $datav);
+ switch ($datav[0]) {
+ case 'max-input-rate':
+ // "Controls the data rate [kbps] at which traffic can be transferred from the user to the [router]."
+ $this->attributes['bw_up'] = radius_cvt_int($datav[1]);
+ break;
+ case 'max-output-rate':
+ //"Controls the data rate [kbps] at which traffic can be transferred from the [router] to the user."
+ $this->attributes['bw_down'] = radius_cvt_int($datav[1]);
+ break;
+ case 'max-input-octets':
+ $this->attributes['maxbytesup'] = radius_cvt_int($datav[1]);
+ break;
+ case 'max-output-octets':
+ $this->attributes['maxbytesdown'] = radius_cvt_int($datav[1]);
+ break;
+ case 'welcome-url':
+ $this->attributes['url_redirection'] = radius_cvt_string($datav[1]);
+ break;
+ case 'goodbye-url':
+ $this->attributes['url_logoff'] = radius_cvt_string($datav[1]);
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case 85: /* Acct-Interim-Interval: RFC 2869 */
+ $this->attributes['interim_interval'] = radius_cvt_int($data);
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ if ($this->res != null) {
+ radius_close($this->res);
+ $this->res = null;
+ }
+ $this->username = str_repeat("\0", strlen($this->username));
+ $this->password = str_repeat("\0", strlen($this->password));
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_PAP
+ *
+ * Class for authenticating using PAP (Plaintext)
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_PAP extends Auth_RADIUS
+{
+
+ /**
+ * Constructor
+ *
+ * @param string $username Username
+ * @param string $password Password
+ * @return void
+ */
+ function Auth_RADIUS_PAP($username = null, $password = null)
+ {
+ $this->Auth_RADIUS();
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+ /**
+ * Creates a RADIUS resource
+ *
+ * Creates a RADIUS resource for authentication. This should be the first
+ * call before you make any other things with the library.
+ *
+ * @return bool true on success, false on error
+ */
+ function open()
+ {
+ $this->res = radius_auth_open();
+ if (!$this->res) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates an authentication request
+ *
+ * Creates an authentication request.
+ * You MUST call this method before you can put any attribute
+ *
+ * @return bool true on success, false on error
+ */
+ function createRequest()
+ {
+ if (!radius_create_request($this->res, RADIUS_ACCESS_REQUEST)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Put authentication specific attributes
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->password)) {
+ $this->putAttribute(RADIUS_USER_PASSWORD, $this->password);
+ }
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_CHAP_MD5
+ *
+ * Class for authenticating using CHAP-MD5 see RFC1994.
+ * Instead og the plaintext password the challenge and
+ * the response are needed.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_CHAP_MD5 extends Auth_RADIUS_PAP
+{
+ /**
+ * 8 Bytes binary challenge
+ * @var string
+ */
+ var $challenge = null;
+
+ /**
+ * 16 Bytes MD5 response binary
+ * @var string
+ */
+ var $response = null;
+
+ /**
+ * Id of the authentication request. Should incremented after every request.
+ * @var integer
+ */
+ var $chapid = 1;
+
+ /**
+ * Constructor
+ *
+ * @param string $username Username
+ * @param string $challenge 8 Bytes Challenge (binary)
+ * @param integer $chapid Requestnumber
+ * @return void
+ */
+ function Auth_RADIUS_CHAP_MD5($username = null, $challenge = null, $chapid = 1)
+ {
+ $this->Auth_RADIUS_PAP();
+ $this->username = $username;
+ $this->challenge = $challenge;
+ $this->chapid = $chapid;
+ }
+
+ /**
+ * Put CHAP-MD5 specific attributes
+ *
+ * For authenticating using CHAP-MD5 via RADIUS you have to put the challenge
+ * and the response. The chapid is inserted in the first byte of the response.
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response)) {
+ $response = pack('C', $this->chapid) . $this->response;
+ $this->putAttribute(RADIUS_CHAP_PASSWORD, $response);
+ }
+ if (isset($this->challenge)) {
+ $this->putAttribute(RADIUS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ Auth_RADIUS_PAP::close();
+ $this->challenge = str_repeat("\0", strlen($this->challenge));
+ $this->response = str_repeat("\0", strlen($this->response));
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_MSCHAPv1
+ *
+ * Class for authenticating using MS-CHAPv1 see RFC2433
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_MSCHAPv1 extends Auth_RADIUS_CHAP_MD5
+{
+ /**
+ * LAN-Manager-Response
+ * @var string
+ */
+ var $lmResponse = null;
+
+ /**
+ * Wether using deprecated LM-Responses or not.
+ * 0 = use LM-Response, 1 = use NT-Response
+ * @var bool
+ */
+ var $flags = 1;
+
+ /**
+ * Put MS-CHAPv1 specific attributes
+ *
+ * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge
+ * and the response. The response has this structure:
+ * struct rad_mschapvalue {
+ * u_char ident;
+ * u_char flags;
+ * u_char lm_response[24];
+ * u_char response[24];
+ * };
+ *
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response) || isset($this->lmResponse)) {
+ $lmResp = isset($this->lmResponse) ? $this->lmResponse : str_repeat ("\0", 24);
+ $ntResp = isset($this->response) ? $this->response : str_repeat ("\0", 24);
+ $resp = pack('CC', $this->chapid, $this->flags) . $lmResp . $ntResp;
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_RESPONSE, $resp);
+ }
+ if (isset($this->challenge)) {
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+}
+
+/**
+ * class Auth_RADIUS_MSCHAPv2
+ *
+ * Class for authenticating using MS-CHAPv2 see RFC2759
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_MSCHAPv2 extends Auth_RADIUS_MSCHAPv1
+{
+ /**
+ * 16 Bytes binary challenge
+ * @var string
+ */
+ var $challenge = null;
+
+ /**
+ * 16 Bytes binary Peer Challenge
+ * @var string
+ */
+ var $peerChallenge = null;
+
+ /**
+ * Put MS-CHAPv2 specific attributes
+ *
+ * For authenticating using MS-CHAPv1 via RADIUS you have to put the challenge
+ * and the response. The response has this structure:
+ * struct rad_mschapv2value {
+ * u_char ident;
+ * u_char flags;
+ * u_char pchallenge[16];
+ * u_char reserved[8];
+ * u_char response[24];
+ * };
+ * where pchallenge is the peer challenge. Like for MS-CHAPv1 we set the flags field to 1.
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ if (isset($this->response) && isset($this->peerChallenge)) {
+ // Response: chapid, flags (1 = use NT Response), Peer challenge, reserved, Response
+ $resp = pack('CCa16a8a24',$this->chapid , 1, $this->peerChallenge, str_repeat("\0", 8), $this->response);
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP2_RESPONSE, $resp);
+ }
+ if (isset($this->challenge)) {
+ $this->putVendorAttribute(RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $this->challenge);
+ }
+ }
+
+ /**
+ * Frees resources.
+ *
+ * Calling this method is always a good idea, because all security relevant
+ * attributes are filled with Nullbytes to leave nothing in the mem.
+ *
+ * @access public
+ */
+ function close()
+ {
+ Auth_RADIUS_MSCHAPv1::close();
+ $this->peerChallenge = str_repeat("\0", strlen($this->peerChallenge));
+ }
+}
+
+/**
+ * class Auth_RADIUS_Acct
+ *
+ * Class for RADIUS accounting
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct extends Auth_RADIUS
+{
+ /**
+ * Defines where the Authentication was made, possible values are:
+ * RADIUS_AUTH_RADIUS, RADIUS_AUTH_LOCAL, RADIUS_AUTH_REMOTE
+ * @var integer
+ */
+ var $authentic = null;
+
+ /**
+ * Defines the type of the accounting request, on of:
+ * RADIUS_START, RADIUS_STOP, RADIUS_ACCOUNTING_ON, RADIUS_ACCOUNTING_OFF
+ * @var integer
+ */
+ var $status_type = null;
+
+ /**
+ * The time the user was logged in in seconds
+ * @var integer
+ */
+ var $session_time = null;
+
+ /**
+ * A uniq identifier for the session of the user, maybe the PHP-Session-Id
+ * @var string
+ */
+ var $session_id = null;
+
+ /**
+ * Constructor
+ *
+ * This function is disabled for M0n0wall since we use our own session_id
+ *
+ * Generates a predefined session_id. We use the Remote-Address, the PID, and the Current user.
+ * @return void
+ *
+ function Auth_RADIUS_Acct()
+ {
+ $this->Auth_RADIUS();
+
+ if (isset($_SERVER)) {
+ $var = &$_SERVER;
+ } else {
+ $var = &$GLOBALS['HTTP_SERVER_VARS'];
+ }
+
+ $this->session_id = sprintf("%s:%d-%s", isset($var['REMOTE_ADDR']) ? $var['REMOTE_ADDR'] : '127.0.0.1' , getmypid(), get_current_user());
+ }
+ */
+
+ /**
+ * Constructor
+ *
+ */
+
+ function Auth_RADIUS_Acct()
+ {
+ $this->Auth_RADIUS();
+ }
+
+ /**
+ * Creates a RADIUS resource
+ *
+ * Creates a RADIUS resource for accounting. This should be the first
+ * call before you make any other things with the library.
+ *
+ * @return bool true on success, false on error
+ */
+ function open()
+ {
+ $this->res = radius_acct_open();
+ if (!$this->res) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates an accounting request
+ *
+ * Creates an accounting request.
+ * You MUST call this method before you can put any attribute.
+ *
+ * @return bool true on success, false on error
+ */
+ function createRequest()
+ {
+ if (!radius_create_request($this->res, RADIUS_ACCOUNTING_REQUEST)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Put attributes for accounting.
+ *
+ * Here we put some accounting values. There many more attributes for accounting,
+ * but for web-applications only certain attributes make sense.
+ * @return void
+ */
+ function putAuthAttributes()
+ {
+ if (isset($this->username)) {
+ $this->putAttribute(RADIUS_USER_NAME, $this->username);
+ }
+ $this->putAttribute(RADIUS_ACCT_STATUS_TYPE, $this->status_type);
+ //if (isset($this->session_time) && $this->status_type == RADIUS_STOP) {
+ if (isset($this->session_time)) {
+ $this->putAttribute(RADIUS_ACCT_SESSION_TIME, $this->session_time);
+ }
+ if (isset($this->authentic)) {
+ $this->putAttribute(RADIUS_ACCT_AUTHENTIC, $this->authentic);
+ }
+
+ $this->putStandardAttributes();
+ }
+
+}
+
+/**
+ * class Auth_RADIUS_Acct_Start
+ *
+ * Class for RADIUS accounting. Its usualy used, after the user has logged in.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Start extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_START by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_START;
+}
+
+/**
+ * class Auth_RADIUS_Acct_Start
+ *
+ * Class for RADIUS accounting. Its usualy used, after the user has logged out.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Stop extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_STOP by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_STOP;
+}
+
+if (!defined('RADIUS_UPDATE'))
+ define('RADIUS_UPDATE', 3);
+
+/**
+ * class Auth_RADIUS_Acct_Update
+ *
+ * Class for interim RADIUS accounting updates.
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Update extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_UPDATE by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_UPDATE;
+}
+
+/**
+ * class Auth_RADIUS_Acct_On
+ *
+ * Class for sending Accounting-On updates
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_On extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_ACCOUNTING_ON by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_ACCOUNTING_ON;
+}
+
+/**
+ * class Auth_RADIUS_Acct_Off
+ *
+ * Class for sending Accounting-Off updates
+ *
+ * @package Auth_RADIUS
+ */
+class Auth_RADIUS_Acct_Off extends Auth_RADIUS_Acct
+{
+ /**
+ * Defines the type of the accounting request.
+ * It is set to RADIUS_ACCOUNTING_OFF by default in this class.
+ * @var integer
+ */
+ var $status_type = RADIUS_ACCOUNTING_OFF;
+}
+
+?>
diff --git a/src/etc/inc/rrd.inc b/src/etc/inc/rrd.inc
new file mode 100644
index 0000000..86148d6
--- /dev/null
+++ b/src/etc/inc/rrd.inc
@@ -0,0 +1,989 @@
+<?php
+/* $Id$ */
+/*
+ rrd.inc
+ Copyright (C) 2010 Seth Mos <seth.mos@dds.nl>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+/*
+ pfSense_BUILDER_BINARIES: /bin/rm /usr/bin/nice /usr/local/bin/rrdtool /bin/cd
+ pfSense_MODULE: rrd
+*/
+
+/* include all configuration functions */
+
+function dump_rrd_to_xml($rrddatabase, $xmldumpfile) {
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+ unlink_if_exists($xmldumpfile);
+
+ exec("$rrdtool dump " . escapeshellarg($rrddatabase) . " {$xmldumpfile} 2>&1", $dumpout, $dumpret);
+ if ($dumpret <> 0) {
+ $dumpout = implode(" ", $dumpout);
+ log_error(sprintf(gettext('RRD dump failed exited with %1$s, the error is: %2$s'), $dumpret, $dumpout));
+ }
+ return($dumpret);
+}
+
+function restore_rrd() {
+ global $g, $config;
+
+ $rrddbpath = "/var/db/rrd/";
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+
+ $rrdrestore = "";
+ $rrdreturn = "";
+ if (file_exists("{$g['cf_conf_path']}/rrd.tgz") && (isset($config['system']['use_mfs_tmpvar']) || $g['platform'] != "pfSense")) {
+ foreach (glob("{$rrddbpath}/*.xml") as $xml_file) {
+ @unlink($xml_file);
+ }
+ unset($rrdrestore);
+ $_gb = exec("cd /;LANG=C /usr/bin/tar -tf {$g['cf_conf_path']}/rrd.tgz", $rrdrestore, $rrdreturn);
+ if ($rrdreturn != 0) {
+ log_error("RRD restore failed exited with $rrdreturn, the error is: $rrdrestore\n");
+ return;
+ }
+ foreach ($rrdrestore as $xml_file) {
+ $rrd_file = '/' . substr($xml_file, 0, -4) . '.rrd';
+ if (file_exists("{$rrd_file}")) {
+ @unlink($rrd_file);
+ }
+ file_put_contents("{$g['tmp_path']}/rrd_restore", $xml_file);
+ $_gb = exec("cd /;LANG=C /usr/bin/tar -xf {$g['cf_conf_path']}/rrd.tgz -T {$g['tmp_path']}/rrd_restore");
+ if (!file_exists("/{$xml_file}")) {
+ log_error("Could not extract {$xml_file} RRD xml file from archive!");
+ continue;
+ }
+ $_gb = exec("$rrdtool restore -f '/{$xml_file}' '{$rrd_file}'", $output, $status);
+ if ($status) {
+ log_error("rrdtool restore -f '{$xml_file}' '{$rrd_file}' failed returning {$status}.");
+ continue;
+ }
+ unset($output);
+ @unlink("/{$xml_file}");
+ }
+ unset($rrdrestore);
+ @unlink("{$g['tmp_path']}/rrd_restore");
+ /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
+ if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
+ unlink_if_exists("{$g['cf_conf_path']}/rrd.tgz");
+ }
+ return true;
+ }
+ return false;
+}
+
+function create_new_rrd($rrdcreatecmd) {
+ $rrdcreateoutput = array();
+ $rrdcreatereturn = 0;
+ $_gb = exec("$rrdcreatecmd 2>&1", $rrdcreateoutput, $rrdcreatereturn);
+ if ($rrdcreatereturn <> 0) {
+ $rrdcreateoutput = implode(" ", $rrdcreateoutput);
+ log_error(sprintf(gettext('RRD create failed exited with %1$s, the error is: %2$s'), $rrdcreatereturn, $rrdcreateoutput));
+ }
+ unset($rrdcreateoutput);
+ return $rrdcreatereturn;
+}
+
+function migrate_rrd_format($rrdoldxml, $rrdnewxml) {
+ if (!file_exists("/tmp/rrd_notice_sent.txt")) {
+ $_gb = exec("echo 'Converting RRD configuration to new format. This might take a bit...' | wall");
+ @touch("/tmp/rrd_notice_sent.txt");
+ }
+ $numrraold = count($rrdoldxml['rra']);
+ $numrranew = count($rrdnewxml['rra']);
+ $numdsold = count($rrdoldxml['ds']);
+ $numdsnew = count($rrdnewxml['ds']);
+ log_error(sprintf(gettext('Import RRD has %1$s DS values and %2$s RRA databases, new format RRD has %3$s DS values and %4$s RRA databases'), $numdsold, $numrraold, $numdsnew , $numrranew));
+
+ /* add data sources not found in the old array from the new array */
+ $i = 0;
+ foreach ($rrdnewxml['ds'] as $ds) {
+ if (!is_array($rrdoldxml['ds'][$i])) {
+ $rrdoldxml['ds'][$i] = $rrdnewxml['ds'][$i];
+ /* set unknown values to 0 */
+ $rrdoldxml['ds'][$i]['last_ds'] = " 0.0000000000e+00 ";
+ $rrdoldxml['ds'][$i]['value'] = " 0.0000000000e+00 ";
+ $rrdoldxml['ds'][$i]['unknown_sec'] = "0";
+ }
+ $i++;
+ }
+
+ $i = 0;
+ $rracountold = count($rrdoldxml['rra']);
+ $rracountnew = count($rrdnewxml['rra']);
+ /* process each RRA, which contain a database */
+ foreach ($rrdnewxml['rra'] as $rra) {
+ if (!is_array($rrdoldxml['rra'][$i])) {
+ $rrdoldxml['rra'][$i] = $rrdnewxml['rra'][$i];
+ }
+
+ $d = 0;
+ /* process cdp_prep */
+ $cdp_prep = $rra['cdp_prep'];
+ foreach ($cdp_prep['ds'] as $ds) {
+ if (!is_array($rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d])) {
+ $rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d] = $rrdnewxml['rra'][$i]['cdp_prep']['ds'][$d];
+ $rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d]['primary_value'] = " 0.0000000000e+00 ";
+ $rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d]['secondary_value'] = " 0.0000000000e+00 ";
+ $rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d]['value'] = " 0.0000000000e+00 ";
+ $rrdoldxml['rra'][$i]['cdp_prep']['ds'][$d]['unknown_datapoints'] = "0";
+ }
+ $d++;
+ }
+
+ /* process database */
+ $rows = $rra['database'];
+ $k = 0;
+ $rowcountold = count($rrdoldxml['rra'][$i]['database']['row']);
+ $rowcountnew = count($rrdnewxml['rra'][$i]['database']['row']);
+ $rowcountdiff = $rowcountnew - $rowcountold;
+ /* save old rows for a bit before we put the required empty rows before it */
+ $rowsdata = $rows;
+ $rowsempty = array();
+ $r = 0;
+ while ($r < $rowcountdiff) {
+ $rowsempty[] = $rrdnewxml['rra'][$i]['database']['row'][$r];
+ $r++;
+ }
+ $rows = $rowsempty + $rowsdata;
+ /* now foreach the rows in the database */
+ foreach ($rows['row'] as $row) {
+ if (!is_array($rrdoldxml['rra'][$i]['database']['row'][$k])) {
+ $rrdoldxml['rra'][$i]['database']['row'][$k] = $rrdnewxml['rra'][$i]['database']['row'][$k];
+ }
+ $m = 0;
+ $vcountold = count($rrdoldxml['rra'][$i]['database']['row'][$k]['v']);
+ $vcountnew = count($rrdnewxml['rra'][$i]['database']['row'][$k]['v']);
+ foreach ($row['v'] as $value) {
+ if (empty($rrdoldxml['rra'][$i]['database']['row'][$k]['v'][$m])) {
+ if (isset($valid)) {
+ $rrdoldxml['rra'][$i]['database']['row'][$k]['v'][$m] = "0.0000000000e+00 ";
+ } else {
+ $rrdoldxml['rra'][$i]['database']['row'][$k]['v'][$m] = $rrdnewxml['rra'][$i]['database']['row'][$k]['v'][$m];
+ }
+ } else {
+ if ($value <> " NaN ") {
+ $valid = true;
+ } else {
+ $valid = false;
+ }
+ }
+ $m++;
+ }
+ $k++;
+ }
+ $i++;
+ }
+
+ $numrranew = count($rrdoldxml['rra']);
+ $numdsnew = count($rrdoldxml['ds']);
+ log_error(sprintf(gettext('The new RRD now has %1$s DS values and %2$s RRA databases'), $numdsnew, $numrranew));
+ return $rrdoldxml;
+}
+
+function enable_rrd_graphing() {
+ global $config, $g, $altq_list_queues;
+
+ if (platform_booting()) {
+ echo gettext("Generating RRD graphs...");
+ }
+
+ $rrddbpath = "/var/db/rrd/";
+ $rrdgraphpath = "/usr/local/www/rrd";
+
+ $traffic = "-traffic.rrd";
+ $packets = "-packets.rrd";
+ $states = "-states.rrd";
+ $wireless = "-wireless.rrd";
+ $queues = "-queues.rrd";
+ $queuesdrop = "-queuedrops.rrd";
+ $spamd = "-spamd.rrd";
+ $proc = "-processor.rrd";
+ $mem = "-memory.rrd";
+ $mbuf = "-mbuf.rrd";
+ $cellular = "-cellular.rrd";
+ $vpnusers = "-vpnusers.rrd";
+ $captiveportalconcurrent = "-concurrent.rrd";
+ $captiveportalloggedin = "-loggedin.rrd";
+ $ntpd = "ntpd.rrd";
+
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+ $netstat = "/usr/bin/netstat";
+ $awk = "/usr/bin/awk";
+ $tar = "/usr/bin/tar";
+ $pfctl = "/sbin/pfctl";
+ $sysctl = "/sbin/sysctl";
+ $php = "/usr/local/bin/php-cgi";
+ $cpustats = "/usr/local/sbin/cpustats";
+ $spamd_gather = "/usr/local/bin/spamd_gather_stats.php";
+ $ifconfig = "/sbin/ifconfig";
+ $captiveportal_gather = "/usr/local/bin/captiveportal_gather_stats.php";
+ $ntpq = "/usr/local/sbin/ntpq";
+
+ $rrdtrafficinterval = 60;
+ $rrdwirelessinterval = 60;
+ $rrdqueuesinterval = 60;
+ $rrdqueuesdropinterval = 60;
+ $rrdpacketsinterval = 60;
+ $rrdstatesinterval = 60;
+ $rrdspamdinterval = 60;
+ $rrdlbpoolinterval = 60;
+ $rrdprocinterval = 60;
+ $rrdmeminterval = 60;
+ $rrdmbufinterval = 60;
+ $rrdcellularinterval = 60;
+ $rrdvpninterval = 60;
+ $rrdcaptiveportalinterval = 60;
+ $rrdntpdinterval = 60;
+
+ $trafficvalid = $rrdtrafficinterval * 2;
+ $wirelessvalid = $rrdwirelessinterval * 2;
+ $queuesvalid = $rrdqueuesinterval * 2;
+ $queuesdropvalid = $rrdqueuesdropinterval * 2;
+ $packetsvalid = $rrdpacketsinterval * 2;
+ $statesvalid = $rrdstatesinterval*2;
+ $spamdvalid = $rrdspamdinterval * 2;
+ $lbpoolvalid = $rrdlbpoolinterval * 2;
+ $procvalid = $rrdlbpoolinterval * 2;
+ $memvalid = $rrdmeminterval * 2;
+ $mbufvalid = $rrdmbufinterval * 2;
+ $cellularvalid = $rrdcellularinterval * 2;
+ $vpnvalid = $rrdvpninterval * 2;
+ $captiveportalvalid = $rrdcaptiveportalinterval * 2;
+ $ntpdvalid = $rrdntpdinterval * 2;
+
+ /* Assume 2*10GigE for now */
+ $downstream = 2500000000;
+ $upstream = 2500000000;
+
+ /* read the shaper config */
+ read_altq_config();
+
+ if (isset ($config['rrd']['enable'])) {
+
+ /* create directory if needed */
+ if (!is_dir($rrddbpath)) {
+ mkdir($rrddbpath, 0775);
+ }
+ chown($rrddbpath, "nobody");
+
+ if (platform_booting()) {
+ restore_rrd();
+ }
+
+ /* db update script */
+ $rrdupdatesh = "#!/bin/sh\n";
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "export TERM=dumb\n";
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= 'echo $$ > ' . $g['varrun_path'] . '/updaterrd.sh.pid';
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "counter=1\n";
+ $rrdupdatesh .= "while [ \"\$counter\" -ne 0 ]\n";
+ $rrdupdatesh .= "do\n";
+ $rrdupdatesh .= "";
+
+ $i = 0;
+ $ifdescrs = get_configured_interface_with_descr();
+ /* IPsec counters */
+ $ifdescrs['ipsec'] = "IPsec";
+ /* OpenVPN server counters */
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $server) {
+ $serverid = "ovpns" . $server['vpnid'];
+ $ifdescrs[$serverid] = "{$server['description']}";
+ }
+ }
+
+ if (platform_booting()) {
+ if (!is_dir("{$g['vardb_path']}/rrd")) {
+ mkdir("{$g['vardb_path']}/rrd", 0775);
+ }
+
+ @chown("{$g['vardb_path']}/rrd", "nobody");
+ }
+
+ /* process all real and pseudo interfaces */
+ foreach ($ifdescrs as $ifname => $ifdescr) {
+ $temp = get_real_interface($ifname);
+ if ($temp <> "") {
+ $realif = $temp;
+ }
+
+ /* TRAFFIC, set up the rrd file */
+ if (!file_exists("$rrddbpath$ifname$traffic")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$traffic --step $rrdtrafficinterval ";
+ $rrdcreate .= "DS:inpass:COUNTER:$trafficvalid:0:$downstream ";
+ $rrdcreate .= "DS:outpass:COUNTER:$trafficvalid:0:$upstream ";
+ $rrdcreate .= "DS:inblock:COUNTER:$trafficvalid:0:$downstream ";
+ $rrdcreate .= "DS:outblock:COUNTER:$trafficvalid:0:$upstream ";
+ $rrdcreate .= "DS:inpass6:COUNTER:$trafficvalid:0:$downstream ";
+ $rrdcreate .= "DS:outpass6:COUNTER:$trafficvalid:0:$upstream ";
+ $rrdcreate .= "DS:inblock6:COUNTER:$trafficvalid:0:$downstream ";
+ $rrdcreate .= "DS:outblock6:COUNTER:$trafficvalid:0:$upstream ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$traffic N:U:U:U:U:U:U:U:U");
+ }
+
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling traffic for interface $ifname $realif IPv4/IPv6 counters \n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$traffic N:";
+ $rrdupdatesh .= "`$pfctl -vvsI -i {$realif} | awk '\\\n";
+ $rrdupdatesh .= "/In4\/Pass/ { b4pi = \$6 };/Out4\/Pass/ { b4po = \$6 };/In4\/Block/ { b4bi = \$6 };/Out4\/Block/ { b4bo = \$6 };\\\n";
+ $rrdupdatesh .= "/In6\/Pass/ { b6pi = \$6 };/Out6\/Pass/ { b6po = \$6 };/In6\/Block/ { b6bi = \$6 };/Out6\/Block/ { b6bo = \$6 };\\\n";
+ $rrdupdatesh .= "END {print b4pi \":\" b4po \":\" b4bi \":\" b4bo \":\" b6pi \":\" b6po \":\" b6bi \":\" b6bo};'`\n";
+
+ /* PACKETS, set up the rrd file */
+ if (!file_exists("$rrddbpath$ifname$packets")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$packets --step $rrdpacketsinterval ";
+ $rrdcreate .= "DS:inpass:COUNTER:$packetsvalid:0:$downstream ";
+ $rrdcreate .= "DS:outpass:COUNTER:$packetsvalid:0:$upstream ";
+ $rrdcreate .= "DS:inblock:COUNTER:$packetsvalid:0:$downstream ";
+ $rrdcreate .= "DS:outblock:COUNTER:$packetsvalid:0:$upstream ";
+ $rrdcreate .= "DS:inpass6:COUNTER:$packetsvalid:0:$downstream ";
+ $rrdcreate .= "DS:outpass6:COUNTER:$packetsvalid:0:$upstream ";
+ $rrdcreate .= "DS:inblock6:COUNTER:$packetsvalid:0:$downstream ";
+ $rrdcreate .= "DS:outblock6:COUNTER:$packetsvalid:0:$upstream ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$packets N:U:U:U:U:U:U:U:U");
+ }
+
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling packets for interface $ifname $realif \n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$packets N:";
+ $rrdupdatesh .= "`$pfctl -vvsI -i {$realif} | awk '\\\n";
+ $rrdupdatesh .= "/In4\/Pass/ { b4pi = \$4 };/Out4\/Pass/ { b4po = \$4 };/In4\/Block/ { b4bi = \$4 };/Out4\/Block/ { b4bo = \$4 };\\\n";
+ $rrdupdatesh .= "/In6\/Pass/ { b6pi = \$4 };/Out6\/Pass/ { b6po = \$4 };/In6\/Block/ { b6bi = \$4 };/Out6\/Block/ { b6bo = \$4 };\\\n";
+ $rrdupdatesh .= "END {print b4pi \":\" b4po \":\" b4bi \":\" b4bo \":\" b6pi \":\" b6po \":\" b6bi \":\" b6bo};'`\n";
+
+ /* WIRELESS, set up the rrd file */
+ if ($config['interfaces'][$ifname]['wireless']['mode'] == "bss") {
+ if (!file_exists("$rrddbpath$ifname$wireless")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$wireless --step $rrdwirelessinterval ";
+ $rrdcreate .= "DS:snr:GAUGE:$wirelessvalid:0:1000 ";
+ $rrdcreate .= "DS:rate:GAUGE:$wirelessvalid:0:1000 ";
+ $rrdcreate .= "DS:channel:GAUGE:$wirelessvalid:0:1000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$wireless N:U:U:U");
+ }
+
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling wireless for interface $ifname $realif \n";
+ $rrdupdatesh .= "WIFI=`$ifconfig {$realif} list sta| $awk 'gsub(\"M\", \"\") {getline 2;print substr(\$5, 0, length(\$5)-2) \":\" $4 \":\" $3}'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$wireless N:\${WIFI}\n";
+ }
+
+ /* OpenVPN, set up the rrd file */
+ if (stristr($ifname, "ovpns")) {
+ if (!file_exists("$rrddbpath$ifname$vpnusers")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$vpnusers --step $rrdvpninterval ";
+ $rrdcreate .= "DS:users:GAUGE:$vpnvalid:0:10000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$vpnusers N:U");
+ }
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $server) {
+ if ("ovpns{$server['vpnid']}" == $ifname) {
+ $port = $server['local_port'];
+ $vpnid = $server['vpnid'];
+ }
+ }
+ }
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling vpn users for interface $ifname $realif port $port\n";
+ $rrdupdatesh .= "list_current_users() {\n";
+ $rrdupdatesh .= " sleep 0.2\n";
+ $rrdupdatesh .= " echo \"status 2\"\n";
+ $rrdupdatesh .= " sleep 0.2\n";
+ $rrdupdatesh .= " echo \"quit\"\n";
+ $rrdupdatesh .= "}\n";
+ $rrdupdatesh .= "OVPN=`list_current_users | nc -U {$g['varetc_path']}/openvpn/server{$vpnid}.sock | awk -F\",\" '/^CLIENT_LIST/ {print \$2}' | wc -l | awk '{print $1}'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$vpnusers N:\${OVPN}\n";
+ }
+
+ /* QUEUES, set up the queues databases */
+ if ($altq_list_queues[$ifname]) {
+ $altq =& $altq_list_queues[$ifname];
+ /* NOTE: Is it worth as its own function?! */
+ switch ($altq->GetBwscale()) {
+ case "Gb":
+ $factor = 1024 * 1024 * 1024;
+ break;
+ case "Mb":
+ $factor = 1024 * 1024;
+ break;
+ case "Kb":
+ $factor = 1024;
+ break;
+ case "b":
+ default:
+ $factor = 1;
+ break;
+ }
+ $qbandwidth = $altq->GetBandwidth() * $factor;
+ if ($qbandwidth <= 0) {
+ $qbandwidth = 100 * 1000 * 1000; /* 100Mbit */
+ }
+ $qlist =& $altq->get_queue_list($notused);
+ if (!file_exists("$rrddbpath$ifname$queues")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$queues --step $rrdqueuesinterval ";
+ /* loop list of shaper queues */
+ $q = 0;
+ foreach ($qlist as $qname => $q) {
+ $rrdcreate .= "DS:$qname:COUNTER:$queuesvalid:0:$qbandwidth ";
+ }
+
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ if (!file_exists("$rrddbpath$ifname$queuesdrop")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$queuesdrop --step $rrdqueuesdropinterval ";
+ /* loop list of shaper queues */
+ $q = 0;
+ foreach ($qlist as $qname => $q) {
+ $rrdcreate .= "DS:$qname:COUNTER:$queuesdropvalid:0:$qbandwidth ";
+ }
+
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ if (platform_booting()) {
+ $rrdqcommand = "-t ";
+ $rrducommand = "N";
+ $qi = 0;
+ foreach ($qlist as $qname => $q) {
+ if ($qi == 0) {
+ $rrdqcommand .= "{$qname}";
+ } else {
+ $rrdqcommand .= ":{$qname}";
+ }
+ $qi++;
+ $rrducommand .= ":U";
+ }
+ mwexec("$rrdtool update $rrddbpath$ifname$queues $rrdqcommand $rrducommand");
+ mwexec("$rrdtool update $rrddbpath$ifname$queuesdrop $rrdqcommand $rrducommand");
+ }
+
+ /* awk function to gather shaper data */
+ /* yes, it's special */
+ $rrdupdatesh .= "` pfctl -vsq -i {$realif} | awk 'BEGIN {printf \"$rrdtool update $rrddbpath$ifname$queues \" } ";
+ $rrdupdatesh .= "{ ";
+ $rrdupdatesh .= "if ((\$1 == \"queue\") && ( \$2 ~ /^q/ )) { ";
+ $rrdupdatesh .= " dsname = dsname \":\" \$2 ; ";
+ $rrdupdatesh .= " q=1; ";
+ $rrdupdatesh .= "} ";
+ $rrdupdatesh .= " else if ((\$4 == \"bytes:\") && ( q == 1 ) ) { ";
+ $rrdupdatesh .= " dsdata = dsdata \":\" \$5 ; ";
+ $rrdupdatesh .= " q=0; ";
+ $rrdupdatesh .= "} ";
+ $rrdupdatesh .= "} END { ";
+ $rrdupdatesh .= " dsname = substr(dsname,2); ";
+ $rrdupdatesh .= " dsdata = substr(dsdata,2); ";
+ $rrdupdatesh .= " printf \"-t \" dsname \" N:\" dsdata }' ";
+ $rrdupdatesh .= " dsname=\"\" dsdata=\"\"`\n\n";
+
+ $rrdupdatesh .= "` pfctl -vsq -i {$realif} | awk 'BEGIN {printf \"$rrdtool update $rrddbpath$ifname$queuesdrop \" } ";
+ $rrdupdatesh .= "{ ";
+ $rrdupdatesh .= "if ((\$1 == \"queue\") && ( \$2 ~ /^q/ )) { ";
+ $rrdupdatesh .= " dsname = dsname \":\" \$2 ; ";
+ $rrdupdatesh .= " q=1; ";
+ $rrdupdatesh .= "} ";
+ $rrdupdatesh .= " else if ((\$4 == \"bytes:\") && ( q == 1 ) ) { ";
+ $rrdupdatesh .= " dsdata = dsdata \":\" \$8 ; ";
+ $rrdupdatesh .= " q=0; ";
+ $rrdupdatesh .= "} ";
+ $rrdupdatesh .= "} END { ";
+ $rrdupdatesh .= " dsname = substr(dsname,2); ";
+ $rrdupdatesh .= " dsdata = substr(dsdata,2); ";
+ $rrdupdatesh .= " printf \"-t \" dsname \" N:\" dsdata }' ";
+ $rrdupdatesh .= " dsname=\"\" dsdata=\"\"`\n\n";
+ }
+
+ /* 3G interfaces */
+ if (preg_match("/ppp[0-9]+/i", $realif)) {
+ if (!file_exists("$rrddbpath$ifname$cellular")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$cellular --step $rrdcellularinterval ";
+ $rrdcreate .= "DS:rssi:GAUGE:$cellularvalid:0:100 ";
+ $rrdcreate .= "DS:upstream:GAUGE:$cellularvalid:0:100000000 ";
+ $rrdcreate .= "DS:downstream:GAUGE:$cellularvalid:0:100000000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$cellular N:U:U:U");
+ }
+
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling 3G\n";
+ $rrdupdatesh .= "GSTATS=`awk -F, 'getline 2 {print \$2 \":\" \$8 \":\" \$9}' < /tmp/3gstats.$ifname`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$cellular N:\"\$GSTATS\"";
+ }
+
+ }
+ $i++;
+
+ /* System only statistics */
+ $ifname = "system";
+
+ /* STATES, create pf states database */
+ if (!file_exists("$rrddbpath$ifname$states")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$states --step $rrdstatesinterval ";
+ $rrdcreate .= "DS:pfrate:GAUGE:$statesvalid:0:10000000 ";
+ $rrdcreate .= "DS:pfstates:GAUGE:$statesvalid:0:10000000 ";
+ $rrdcreate .= "DS:pfnat:GAUGE:$statesvalid:0:10000000 ";
+ $rrdcreate .= "DS:srcip:GAUGE:$statesvalid:0:10000000 ";
+ $rrdcreate .= "DS:dstip:GAUGE:$statesvalid:0:10000000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$states N:U:U:U:U:U");
+ }
+
+ /* the pf states gathering function. */
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "pfctl_si_out=\"` $pfctl -si > /tmp/pfctl_si_out `\"\n";
+ $rrdupdatesh .= "pfctl_ss_out=\"` $pfctl -ss > /tmp/pfctl_ss_out`\"\n";
+ $rrdupdatesh .= "pfrate=\"` cat /tmp/pfctl_si_out | egrep \"inserts|removals\" | awk '{ pfrate = \$3 + pfrate } {print pfrate}'|tail -1 `\"\n";
+ $rrdupdatesh .= "pfstates=\"` cat /tmp/pfctl_ss_out | egrep -v \"<\\-.*?<\\-|\\->.*?\\->\" | wc -l|sed 's/ //g'`\"\n";
+ $rrdupdatesh .= "pfnat=\"` cat /tmp/pfctl_ss_out | egrep '<\\-.*?<\\-|\\->.*?\\->' | wc -l|sed 's/ //g' `\"\n";
+ $rrdupdatesh .= "srcip=\"` cat /tmp/pfctl_ss_out | egrep -v '<\\-.*?<\\-|\\->.*?\\->' | grep '\\->' | awk '{print \$3}' | awk -F: '{print \$1}' | sort -u|wc -l|sed 's/ //g' `\"\n";
+ $rrdupdatesh .= "dstip=\"` cat /tmp/pfctl_ss_out | egrep -v '<\\-.*?<\\-|\\->.*?\\->' | grep '<\\-' | awk '{print \$3}' | awk -F: '{print \$1}' | sort -u|wc -l|sed 's/ //g' `\"\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$states N:\$pfrate:\$pfstates:\$pfnat:\$srcip:\$dstip\n\n";
+
+ /* End pf states statistics */
+
+ /* CPU, create CPU statistics database */
+ if (!file_exists("$rrddbpath$ifname$proc")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$proc --step $rrdprocinterval ";
+ $rrdcreate .= "DS:user:GAUGE:$procvalid:0:10000000 ";
+ $rrdcreate .= "DS:nice:GAUGE:$procvalid:0:10000000 ";
+ $rrdcreate .= "DS:system:GAUGE:$procvalid:0:10000000 ";
+ $rrdcreate .= "DS:interrupt:GAUGE:$procvalid:0:10000000 ";
+ $rrdcreate .= "DS:processes:GAUGE:$procvalid:0:10000000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$proc N:U:U:U:U:U");
+ }
+
+ /* the CPU stats gathering function. */
+ $rrdupdatesh .= "CPU=`$cpustats | cut -f1-4 -d':'`\n";
+ /* Using ps uxaH will count all processes including system threads. Top was undercounting. */
+ $rrdupdatesh .= "PROCS=`ps uxaH | wc -l | awk '{print \$1;}'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$proc N:\${CPU}:\${PROCS}\n";
+
+ /* End CPU statistics */
+
+ /* Memory, create Memory statistics database */
+ if (!file_exists("$rrddbpath$ifname$mem")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$mem --step $rrdmeminterval ";
+ $rrdcreate .= "DS:active:GAUGE:$memvalid:0:10000000 ";
+ $rrdcreate .= "DS:inactive:GAUGE:$memvalid:0:10000000 ";
+ $rrdcreate .= "DS:free:GAUGE:$memvalid:0:10000000 ";
+ $rrdcreate .= "DS:cache:GAUGE:$memvalid:0:10000000 ";
+ $rrdcreate .= "DS:wire:GAUGE:$memvalid:0:10000000 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$mem N:U:U:U:U:U");
+ }
+
+ /* the Memory stats gathering function. */
+ $rrdupdatesh .= "MEM=`$sysctl -n vm.stats.vm.v_page_count vm.stats.vm.v_active_count vm.stats.vm.v_inactive_count vm.stats.vm.v_free_count vm.stats.vm.v_cache_count vm.stats.vm.v_wire_count | ";
+ $rrdupdatesh .= " $awk '{getline active;getline inactive;getline free;getline cache;getline wire;printf ";
+ $rrdupdatesh .= "((active/$0) * 100)\":\"((inactive/$0) * 100)\":\"((free/$0) * 100)\":\"((cache/$0) * 100)\":\"(wire/$0 * 100)}'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$mem N:\${MEM}\n";
+
+ /* End Memory statistics */
+
+ /* mbuf, create mbuf statistics database */
+ if (!file_exists("$rrddbpath$ifname$mbuf")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$mbuf --step $rrdmbufinterval ";
+ $rrdcreate .= "DS:current:GAUGE:$mbufvalid:0:10000000 ";
+ $rrdcreate .= "DS:cache:GAUGE:$mbufvalid:0:10000000 ";
+ $rrdcreate .= "DS:total:GAUGE:$mbufvalid:0:10000000 ";
+ $rrdcreate .= "DS:max:GAUGE:$mbufvalid:0:10000000 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ifname$mbuf N:U:U:U:U");
+ }
+
+ /* the mbuf stats gathering function. */
+ $rrdupdatesh .= "MBUF=`$netstat -m | ";
+ $rrdupdatesh .= " $awk '/mbuf clusters in use/ { gsub(/\//, \":\", $1); print $1; }'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$mbuf N:\${MBUF}\n";
+
+ /* End mbuf statistics */
+
+ /* SPAMD, set up the spamd rrd file */
+ if (isset($config['installedpackages']['spamdsettings']) &&
+ $config['installedpackages']['spamdsettings']['config'][0]['enablerrd']) {
+ /* set up the spamd rrd file */
+ if (!file_exists("$rrddbpath$ifname$spamd")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ifname$spamd --step $rrdspamdinterval ";
+ $rrdcreate .= "DS:conn:GAUGE:$spamdvalid:0:10000 ";
+ $rrdcreate .= "DS:time:GAUGE:$spamdvalid:0:86400 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling spamd for connections and tarpitness \n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ifname$spamd \\\n";
+ $rrdupdatesh .= "`$php -q $spamd_gather`\n";
+
+ }
+ /* End System statistics */
+
+ /* Captive Portal statistics, set up the rrd file */
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpkey => $cp) {
+ if (!isset($cp['enable'])) {
+ continue;
+ }
+
+ $ifname= "captiveportal";
+ $concurrent_filename = $rrddbpath . $ifname . '-' . $cpkey . $captiveportalconcurrent;
+ if (!file_exists("$concurrent_filename")) {
+ $rrdcreate = "$rrdtool create $concurrent_filename --step $rrdcaptiveportalinterval ";
+ $rrdcreate .= "DS:concurrentusers:GAUGE:$captiveportalvalid:0:10000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:LAST:0.5:1:1200 ";
+ $rrdcreate .= "RRA:LAST:0.5:5:720 ";
+ $rrdcreate .= "RRA:LAST:0.5:60:1860 ";
+ $rrdcreate .= "RRA:LAST:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $concurrent_filename N:U");
+ }
+
+ /* the Captive Portal stats gathering function. */
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling Captive Portal for number of concurrent users\n";
+ $rrdupdatesh .= "CP=`${php} -q ${captiveportal_gather} '${cpkey}' 'concurrent'`\n";
+ $rrdupdatesh .= "$rrdtool update $concurrent_filename \${CP}\n";
+
+ $loggedin_filename = $rrddbpath . $ifname . '-' . $cpkey . $captiveportalloggedin;
+ if (!file_exists("$loggedin_filename")) {
+ $rrdcreate = "$rrdtool create $loggedin_filename --step $rrdcaptiveportalinterval ";
+ $rrdcreate .= "DS:loggedinusers:GAUGE:$captiveportalvalid:0:10000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:LAST:0.5:1:1200 ";
+ $rrdcreate .= "RRA:LAST:0.5:5:720 ";
+ $rrdcreate .= "RRA:LAST:0.5:60:1860 ";
+ $rrdcreate .= "RRA:LAST:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $loggedin_filename N:U");
+ }
+
+ /* the Captive Portal stats gathering function. */
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "# polling Captive Portal for number of logged in users\n";
+ $rrdupdatesh .= "CP=`${php} -q ${captiveportal_gather} '${cpkey}' 'loggedin'`\n";
+ $rrdupdatesh .= "$rrdtool update $loggedin_filename \${CP}\n";
+
+ }
+ }
+ /* End Captive Portal statistics */
+
+ /* NTP, set up the ntpd rrd file */
+ if (isset($config['ntpd']['statsgraph'])) {
+ /* set up the ntpd rrd file */
+ if (!file_exists("$rrddbpath$ntpd")) {
+ $rrdcreate = "$rrdtool create $rrddbpath$ntpd --step $rrdntpdinterval ";
+ $rrdcreate .= "DS:offset:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "DS:sjit:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "DS:cjit:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "DS:wander:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "DS:freq:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "DS:disp:GAUGE:$ntpdvalid:0:1000 ";
+ $rrdcreate .= "RRA:MIN:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MIN:0.5:5:720 ";
+ $rrdcreate .= "RRA:MIN:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MIN:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+ $rrdcreate .= "RRA:MAX:0.5:1:1200 ";
+ $rrdcreate .= "RRA:MAX:0.5:5:720 ";
+ $rrdcreate .= "RRA:MAX:0.5:60:1860 ";
+ $rrdcreate .= "RRA:MAX:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ mwexec("$rrdtool update $rrddbpath$ntpd N:U:U:U:U:U:U");
+ }
+
+ /* the ntp stats gathering function. */
+ $rrdupdatesh .= "\n";
+ $rrdupdatesh .= "$ntpq -c rv | $awk 'BEGIN{ RS=\",\"}{ print }' >> /tmp/ntp-rrdstats.$$\n";
+ $rrdupdatesh .= "NOFFSET=`grep offset /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "NFREQ=`grep frequency /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "NSJIT=`grep sys_jitter /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "NCJIT=`grep clk_jitter /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "NWANDER=`grep clk_wander /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "NDISPER=`grep rootdisp /tmp/ntp-rrdstats.$$ | awk 'BEGIN{FS=\"=\"}{print $2}'`\n";
+ $rrdupdatesh .= "$rrdtool update $rrddbpath$ntpd \N:\${NOFFSET}:\${NSJIT}:\${NCJIT}:\${NWANDER}:\${NFREQ}:\${NDISPER}\n";
+ $rrdupdatesh .= "rm /tmp/ntp-rrdstats.$$\n";
+ $rrdupdatesh .= "\n";
+
+ }
+ /* End NTP statistics */
+
+ $rrdupdatesh .= "sleep 60\n";
+ $rrdupdatesh .= "done\n";
+ log_error(gettext("Creating rrd update script"));
+ /* write the rrd update script */
+ $updaterrdscript = "{$g['vardb_path']}/rrd/updaterrd.sh";
+ $fd = fopen("$updaterrdscript", "w");
+ fwrite($fd, "$rrdupdatesh");
+ fclose($fd);
+
+ unset($rrdupdatesh);
+
+ /* kill off traffic collectors */
+ kill_traffic_collector();
+
+ /* start traffic collector */
+ mwexec_bg("/usr/bin/nice -n20 /bin/sh $updaterrdscript");
+
+ } else {
+ /* kill off traffic collectors */
+ kill_traffic_collector();
+ }
+
+ $databases = glob("{$rrddbpath}/*.rrd");
+ foreach ($databases as $database) {
+ chown($database, "nobody");
+ }
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+
+}
+
+# Create gateway quality RRD with settings suitable for pfSense graph set.
+function create_gateway_quality_rrd($rrd_file) {
+ global $g;
+
+ $rrdinterval = 60;
+ $valid = $rrdinterval * 2;
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+
+ /* GATEWAY QUALITY, set up the rrd file */
+ if (!file_exists("$rrd_file")) {
+ $rrdcreate = "$rrdtool create $rrd_file --step $rrdinterval ";
+ $rrdcreate .= "DS:loss:GAUGE:$valid:0:100 ";
+ $rrdcreate .= "DS:delay:GAUGE:$valid:0:100000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1200 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:720 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1860 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1440:2284 ";
+
+ create_new_rrd($rrdcreate);
+ unset($rrdcreate);
+ }
+
+ /* enter UNKNOWN values in the RRD so it knows we rebooted. */
+ if (platform_booting()) {
+ if (!is_dir("{$g['vardb_path']}/rrd")) {
+ mkdir("{$g['vardb_path']}/rrd", 0775);
+ }
+
+ @chown("{$g['vardb_path']}/rrd", "nobody");
+
+ mwexec("$rrdtool update $rrd_file N:U:U");
+ }
+ unset($rrdtool, $rrdinterval, $valid, $rrd_file);
+}
+
+function kill_traffic_collector() {
+ global $g;
+
+ killbypid("{$g['varrun_path']}/updaterrd.sh.pid");
+}
+
+?>
diff --git a/src/etc/inc/sasl.inc b/src/etc/inc/sasl.inc
new file mode 100644
index 0000000..a9582da
--- /dev/null
+++ b/src/etc/inc/sasl.inc
@@ -0,0 +1,422 @@
+<?php
+/*
+ * sasl.php
+ *
+ * @(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $
+ *
+ */
+
+define("SASL_INTERACT", 2);
+define("SASL_CONTINUE", 1);
+define("SASL_OK", 0);
+define("SASL_FAIL", -1);
+define("SASL_NOMECH", -4);
+
+class sasl_interact_class
+{
+ var $id;
+ var $challenge;
+ var $prompt;
+ var $default_result;
+ var $result;
+};
+
+/*
+{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
+<class>
+
+ <package>net.manuellemos.sasl</package>
+
+ <version>@(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $</version>
+ <copyright>Copyright © (C) Manuel Lemos 2004</copyright>
+ <title>Simple Authentication and Security Layer client</title>
+ <author>Manuel Lemos</author>
+ <authoraddress>mlemos-at-acm.org</authoraddress>
+
+ <documentation>
+ <idiom>en</idiom>
+ <purpose>Provide a common interface to plug-in driver classes that
+ implement different mechanisms for authentication used by clients of
+ standard protocols like SMTP, POP3, IMAP, HTTP, etc.. Currently the
+ supported authentication mechanisms are: <tt>PLAIN</tt>,
+ <tt>LOGIN</tt>, <tt>CRAM-MD5</tt>, <tt>Digest</tt> and <tt>NTML</tt>
+ (Windows or Samba).</purpose>
+ <usage>.</usage>
+ </documentation>
+
+{/metadocument}
+*/
+
+class sasl_client_class
+{
+ /* Public variables */
+
+/*
+{metadocument}
+ <variable>
+ <name>error</name>
+ <type>STRING</type>
+ <value></value>
+ <documentation>
+ <purpose>Store the message that is returned when an error
+ occurs.</purpose>
+ <usage>Check this variable to understand what happened when a call to
+ any of the class functions has failed.<paragraphbreak />
+ This class uses cumulative error handling. This means that if one
+ class functions that may fail is called and this variable was
+ already set to an error message due to a failure in a previous call
+ to the same or other function, the function will also fail and does
+ not do anything.<paragraphbreak />
+ This allows programs using this class to safely call several
+ functions that may fail and only check the failure condition after
+ the last function call.<paragraphbreak />
+ Just set this variable to an empty string to clear the error
+ condition.</usage>
+ </documentation>
+ </variable>
+{/metadocument}
+*/
+ var $error='';
+
+/*
+{metadocument}
+ <variable>
+ <name>mechanism</name>
+ <type>STRING</type>
+ <value></value>
+ <documentation>
+ <purpose>Store the name of the mechanism that was selected during the
+ call to the <functionlink>Start</functionlink> function.</purpose>
+ <usage>You can access this variable but do not change it.</usage>
+ </documentation>
+ </variable>
+{/metadocument}
+*/
+ var $mechanism='';
+
+/*
+{metadocument}
+ <variable>
+ <name>encode_response</name>
+ <type>BOOLEAN</type>
+ <value>1</value>
+ <documentation>
+ <purpose>Let the drivers inform the applications whether responses
+ need to be encoded.</purpose>
+ <usage>Applications should check this variable before sending
+ authentication responses to the server to determine if the
+ responses need to be encoded, eventually with base64 algorithm.</usage>
+ </documentation>
+ </variable>
+{/metadocument}
+*/
+ var $encode_response=1;
+
+ /* Private variables */
+
+ var $driver;
+ var $drivers=array(
+ "Digest" => array("digest_sasl_client_class", "digest_sasl_client.inc" ),
+ "CRAM-MD5" => array("cram_md5_sasl_client_class", "cram_md5_sasl_client.inc" ),
+ "LOGIN" => array("login_sasl_client_class", "login_sasl_client.inc" ),
+ "NTLM" => array("ntlm_sasl_client_class", "ntlm_sasl_client.inc" ),
+ "PLAIN" => array("plain_sasl_client_class", "plain_sasl_client.inc" ),
+ "Basic" => array("basic_sasl_client_class", "basic_sasl_client.inc" )
+ );
+ var $credentials=array();
+
+ /* Public functions */
+
+/*
+{metadocument}
+ <function>
+ <name>SetCredential</name>
+ <type>VOID</type>
+ <documentation>
+ <purpose>Store the value of a credential that may be used by any of
+ the supported mechanisms to process the authentication messages and
+ responses.</purpose>
+ <usage>Call this function before starting the authentication dialog
+ to pass all the credential values that be needed to use the type
+ of authentication that the applications may need.</usage>
+ <returnvalue>.</returnvalue>
+ </documentation>
+ <argument>
+ <name>key</name>
+ <type>STRING</type>
+ <documentation>
+ <purpose>Specify the name of the credential key.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>value</name>
+ <type>STRING</type>
+ <documentation>
+ <purpose>Specify the value for the credential.</purpose>
+ </documentation>
+ </argument>
+ <do>
+{/metadocument}
+*/
+ Function SetCredential($key,$value)
+ {
+ $this->credentials[$key]=$value;
+ }
+/*
+{metadocument}
+ </do>
+ </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+ <function>
+ <name>GetCredentials</name>
+ <type>INTEGER</type>
+ <documentation>
+ <purpose>Retrieve the values of one or more credentials to be used by
+ the authentication mechanism classes.</purpose>
+ <usage>This is meant to be used by authentication mechanism driver
+ classes to retrieve the credentials that may be needed.</usage>
+ <returnvalue>The function may return <tt>SASL_CONTINUE</tt> if it
+ succeeded, or <tt>SASL_NOMECH</tt> if it was not possible to
+ retrieve one of the requested credentials.</returnvalue>
+ </documentation>
+ <argument>
+ <name>credentials</name>
+ <type>HASH</type>
+ <documentation>
+ <purpose>Reference to an associative array variable with all the
+ credentials that are being requested. The function initializes
+ this associative array values.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>defaults</name>
+ <type>HASH</type>
+ <documentation>
+ <purpose>Associative arrays with default values for credentials
+ that may have not been defined.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>interactions</name>
+ <type>ARRAY</type>
+ <documentation>
+ <purpose>Not yet in use. It is meant to provide context
+ information to retrieve credentials that may be obtained
+ interacting with the user.</purpose>
+ </documentation>
+ </argument>
+ <do>
+{/metadocument}
+*/
+ Function GetCredentials(&$credentials,$defaults,&$interactions)
+ {
+ Reset($credentials);
+ $end=(GetType($key=Key($credentials))!="string");
+ for(;!$end;)
+ {
+ if(!IsSet($this->credentials[$key]))
+ {
+ if(IsSet($defaults[$key]))
+ $credentials[$key]=$defaults[$key];
+ else
+ {
+ $this->error="the requested credential ".$key." is not defined";
+ return(SASL_NOMECH);
+ }
+ }
+ else
+ $credentials[$key]=$this->credentials[$key];
+ Next($credentials);
+ $end=(GetType($key=Key($credentials))!="string");
+ }
+ return(SASL_CONTINUE);
+ }
+/*
+{metadocument}
+ </do>
+ </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+ <function>
+ <name>Start</name>
+ <type>INTEGER</type>
+ <documentation>
+ <purpose>Process the initial authentication step initializing the
+ driver class that implements the first of the list of requested
+ mechanisms that is supported by this SASL client library
+ implementation.</purpose>
+ <usage>Call this function specifying a list of mechanisms that the
+ server supports. If the <argumentlink>
+ <argument>message</argument>
+ <function>Start</function>
+ </argumentlink> argument returns a string, it should be sent to
+ the server as initial message. Check the
+ <variablelink>encode_response</variablelink> variable to determine
+ whether the initial message needs to be encoded, eventually with
+ base64 algorithm, before it is sent to the server.</usage>
+ <returnvalue>The function may return <tt>SASL_CONTINUE</tt> if it
+ could start one of the requested authentication mechanisms. It
+ may return <tt>SASL_NOMECH</tt> if it was not possible to start
+ any of the requested mechanisms. It returns <tt>SASL_FAIL</tt> or
+ other value in case of error.</returnvalue>
+ </documentation>
+ <argument>
+ <name>mechanisms</name>
+ <type>ARRAY</type>
+ <inout />
+ <documentation>
+ <purpose>Define the list of names of authentication mechanisms
+ supported by the that should be tried.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>message</name>
+ <type>STRING</type>
+ <out />
+ <documentation>
+ <purpose>Return the initial message that should be sent to the
+ server to start the authentication dialog. If this value is
+ undefined, no message should be sent to the server.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>interactions</name>
+ <type>ARRAY</type>
+ <documentation>
+ <purpose>Not yet in use. It is meant to provide context
+ information to interact with the end user.</purpose>
+ </documentation>
+ </argument>
+ <do>
+{/metadocument}
+*/
+ Function Start($mechanisms, &$message, &$interactions)
+ {
+ if(strlen($this->error))
+ return(SASL_FAIL);
+ if(IsSet($this->driver))
+ return($this->driver->Start($this,$message,$interactions));
+ $no_mechanism_error="";
+ for($m=0;$m<count($mechanisms);$m++)
+ {
+ $mechanism=$mechanisms[$m];
+ if(IsSet($this->drivers[$mechanism]))
+ {
+ if(!class_exists($this->drivers[$mechanism][0]))
+ require(dirname(__FILE__)."/".$this->drivers[$mechanism][1]);
+ $this->driver=new $this->drivers[$mechanism][0];
+ if($this->driver->Initialize($this))
+ {
+ $this->encode_response=1;
+ $status=$this->driver->Start($this,$message,$interactions);
+ switch($status)
+ {
+ case SASL_NOMECH:
+ Unset($this->driver);
+ if(strlen($no_mechanism_error)==0)
+ $no_mechanism_error=$this->error;
+ $this->error="";
+ break;
+ case SASL_CONTINUE:
+ $this->mechanism=$mechanism;
+ return($status);
+ default:
+ Unset($this->driver);
+ $this->error="";
+ return($status);
+ }
+ }
+ else
+ {
+ Unset($this->driver);
+ if(strlen($no_mechanism_error)==0)
+ $no_mechanism_error=$this->error;
+ $this->error="";
+ }
+ }
+ }
+ $this->error=(strlen($no_mechanism_error) ? $no_mechanism_error : "it was not requested any of the authentication mechanisms that are supported");
+ return(SASL_NOMECH);
+ }
+/*
+{metadocument}
+ </do>
+ </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+ <function>
+ <name>Step</name>
+ <type>INTEGER</type>
+ <documentation>
+ <purpose>Process the authentication steps after the initial step,
+ until the authentication iteration dialog is complete.</purpose>
+ <usage>Call this function iteratively after a successful initial
+ step calling the <functionlink>Start</functionlink> function.</usage>
+ <returnvalue>The function returns <tt>SASL_CONTINUE</tt> if step was
+ processed successfully, or returns <tt>SASL_FAIL</tt> in case of
+ error.</returnvalue>
+ </documentation>
+ <argument>
+ <name>response</name>
+ <type>STRING</type>
+ <in />
+ <documentation>
+ <purpose>Pass the response returned by the server to the previous
+ step.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>message</name>
+ <type>STRING</type>
+ <out />
+ <documentation>
+ <purpose>Return the message that should be sent to the server to
+ continue the authentication dialog. If this value is undefined,
+ no message should be sent to the server.</purpose>
+ </documentation>
+ </argument>
+ <argument>
+ <name>interactions</name>
+ <type>ARRAY</type>
+ <documentation>
+ <purpose>Not yet in use. It is meant to provide context
+ information to interact with the end user.</purpose>
+ </documentation>
+ </argument>
+ <do>
+{/metadocument}
+*/
+ Function Step($response, &$message, &$interactions)
+ {
+ if(strlen($this->error))
+ return(SASL_FAIL);
+ return($this->driver->Step($this,$response,$message,$interactions));
+ }
+/*
+{metadocument}
+ </do>
+ </function>
+{/metadocument}
+*/
+
+};
+
+/*
+
+{metadocument}
+</class>
+{/metadocument}
+
+*/
+
+?>
diff --git a/src/etc/inc/service-utils.inc b/src/etc/inc/service-utils.inc
new file mode 100644
index 0000000..77a7914
--- /dev/null
+++ b/src/etc/inc/service-utils.inc
@@ -0,0 +1,749 @@
+<?php
+/****h* pfSense/service-utils
+ NAME
+ service-utils.inc - Service facility
+ DESCRIPTION
+ This file contains various functions used by the pfSense service facility.
+ HISTORY
+ $Id$
+
+ Copyright (C) 2005-2006 Colin Smith (ethethlay@gmail.com)
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+/*
+ pfSense_BUILDER_BINARIES: /bin/pgrep /bin/sh /usr/bin/killall
+ pfSense_MODULE: utils
+*/
+require_once("globals.inc");
+require_once("captiveportal.inc");
+require_once("openvpn.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+require_once("vslb.inc");
+require_once("gwlb.inc");
+
+define("RCFILEPREFIX", "/usr/local/etc/rc.d/");
+function write_rcfile($params) {
+ global $g;
+
+ safe_mkdir(RCFILEPREFIX);
+ $rcfile_fullname = RCFILEPREFIX . $params['file'];
+ if (!file_exists($rcfile_fullname) && !is_link($rcfile_fullname) && !touch($rcfile_fullname)) {
+ return false;
+ }
+
+ if (!is_writable($rcfile_fullname) || empty($params['start'])) {
+ return false;
+ }
+
+ $towrite = "#!/bin/sh\n";
+ $towrite .= "# This file was automatically generated\n# by the {$g['product_name']} service handler.\n\n";
+
+ /* write our rc functions */
+ $towrite .= "rc_start() {\n";
+ $towrite .= "\t{$params['start']}\n";
+ $towrite .= "}\n\n";
+ if (!empty($params['stop'])) {
+ $tokill =& $params['stop'];
+ } else if (!empty($params['executable'])) {
+ /* just nuke the executable */
+ $tokill = "/usr/bin/killall " . escapeshellarg($params['executable']);
+ } else {
+ /* make an educated guess (bad) */
+ $tokill = array_pop(explode('/', array_shift(explode(' ', $params['start']))));
+ }
+ $towrite .= "rc_stop() {\n";
+ $towrite .= "\t{$tokill}\n";
+ $towrite .= "}\n\n";
+
+ /* begin rcfile logic */
+ $towrite .= "case \$1 in\n\tstart)\n\t\trc_start\n\t\t;;\n\tstop)\n\t\trc_stop\n\t\t;;\n\trestart)\n\t\trc_stop\n\t\trc_start\n\t\t;;\nesac\n\n";
+
+ @file_put_contents($rcfile_fullname, $towrite);
+ unset($towrite);
+ @chmod("{$rcfile_fullname}", 0755);
+
+ return;
+}
+
+function start_service($name) {
+ global $config;
+
+ if (empty($name)) {
+ return;
+ }
+
+ if (is_array($config['installedpackages']) && is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $service) {
+ if (strtolower($service['name']) == strtolower($name)) {
+ if ($service['rcfile']) {
+ $prefix = RCFILEPREFIX;
+ if (!empty($service['prefix'])) {
+ $prefix =& $service['prefix'];
+ }
+ if (file_exists("{$prefix}{$service['rcfile']}") || is_link("{$prefix}{$service['rcfile']}")) {
+ mwexec_bg("{$prefix}{$service['rcfile']} start");
+ }
+ }
+ if (!empty($service['startcmd'])) {
+ eval($service['startcmd']);
+ }
+ break;
+ }
+ }
+ }
+}
+
+function stop_service($name) {
+ global $config;
+
+ if (empty($name)) {
+ return;
+ }
+
+ if (is_array($config['installedpackages']) && is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $service) {
+ if (strtolower($service['name']) == strtolower($name)) {
+ if ($service['rcfile']) {
+ $prefix = RCFILEPREFIX;
+ if (!empty($service['prefix'])) {
+ $prefix =& $service['prefix'];
+ }
+ if (file_exists("{$prefix}{$service['rcfile']}") || is_link("{$prefix}{$service['rcfile']}")) {
+ mwexec("{$prefix}{$service['rcfile']} stop");
+ }
+ return;
+ }
+ if (!empty($service['stopcmd'])) {
+ eval($service['stopcmd']);
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+function restart_service($name) {
+ global $config;
+
+ if (empty($name)) {
+ return;
+ }
+
+ stop_service($name);
+ start_service($name);
+
+ if (is_array($config['installedpackages']) && is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $service) {
+ if (strtolower($service['name']) == strtolower($name)) {
+ if ($service['restartcmd']) {
+ eval($service['restartcmd']);
+ }
+ break;
+ }
+ }
+ }
+}
+
+function is_pid_running($pidfile) {
+ if (!file_exists($pidfile)) {
+ return false;
+ }
+
+ return (isvalidpid($pidfile));
+}
+
+function is_dhcp_running($interface) {
+ $status = find_dhclient_process($interface);
+ if ($status != 0) {
+ return true;
+ }
+ return false;
+}
+
+function restart_service_if_running($service) {
+ global $config;
+ if (is_service_running($service)) {
+ restart_service($service);
+ }
+ return;
+}
+
+function is_service_enabled($service_name) {
+ global $config;
+ if ($service_name == "") {
+ return false;
+ }
+ if (is_array($config['installedpackages'])) {
+ if (isset($config['installedpackages'][$service_name]['config'][0]['enable']) &&
+ ((empty($config['installedpackages'][$service_name]['config'][0]['enable'])) ||
+ ($config['installedpackages'][$service_name]['config'][0]['enable'] === 'off'))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function is_service_running($service, $ps = "") {
+ global $config;
+
+ if (is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $aservice) {
+ if (strtolower($service) == strtolower($aservice['name'])) {
+ if ($aservice['custom_php_service_status_command'] <> "") {
+ eval("\$rc={$aservice['custom_php_service_status_command']};");
+ return $rc;
+ }
+ if (empty($aservice['executable'])) {
+ return false;
+ }
+ if (is_process_running($aservice['executable'])) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (is_process_running($service)) {
+ return true;
+ }
+
+ return false;
+}
+
+function get_services() {
+ global $config;
+ if (is_array($config['installedpackages']['service'])) {
+ $services = $config['installedpackages']['service'];
+ } else {
+ $services = array();
+ }
+
+ /*
+ * Add services that are in the base.
+ */
+ if (is_radvd_enabled()) {
+ $pconfig = array();
+ $pconfig['name'] = "radvd";
+ $pconfig['description'] = gettext("Router Advertisement Daemon");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['dnsmasq']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "dnsmasq";
+ $pconfig['description'] = gettext("DNS Forwarder");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['unbound']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "unbound";
+ $pconfig['description'] = gettext("DNS Resolver");
+ $services[] = $pconfig;
+ }
+
+ $pconfig = array();
+ $pconfig['name'] = "ntpd";
+ $pconfig['description'] = gettext("NTP clock sync");
+ $services[] = $pconfig;
+
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $zone => $setting) {
+ if (isset($setting['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "captiveportal";
+ $pconfig['zone'] = $zone;
+ $pconfig['description'] = gettext("Captive Portal") . ": ".htmlspecialchars($setting['zone']);
+ $services[] = $pconfig;
+ }
+ }
+ }
+
+ $iflist = array();
+ $ifdescrs = get_configured_interface_list();
+ foreach ($ifdescrs as $if) {
+ $oc = $config['interfaces'][$if];
+ if ($oc['if'] && (!link_interface_to_bridge($if))) {
+ $iflist[$if] = $if;
+ }
+ }
+
+ if (isset($config['dhcrelay']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "dhcrelay";
+ $pconfig['description'] = gettext("DHCP Relay");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['dhcrelay6']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "dhcrelay6";
+ $pconfig['description'] = gettext("DHCPv6 Relay");
+ $services[] = $pconfig;
+ }
+
+ if (is_dhcp_server_enabled()) {
+ $pconfig = array();
+ $pconfig['name'] = "dhcpd";
+ $pconfig['description'] = gettext("DHCP Service");
+ $services[] = $pconfig;
+ }
+
+ $gateways_arr = return_gateways_array();
+ if (is_array($gateways_arr)) {
+ $pconfig = array();
+ $pconfig['name'] = "apinger";
+ $pconfig['description'] = gettext("Gateway Monitoring Daemon");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['snmpd']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "bsnmpd";
+ $pconfig['description'] = gettext("SNMP Service");
+ $services[] = $pconfig;
+ }
+
+ if (is_array($config['igmpproxy']['igmpentry']) && (count($config['igmpproxy']['igmpentry']) > 0)) {
+ $pconfig = array();
+ $pconfig['name'] = "igmpproxy";
+ $pconfig['description'] = gettext("IGMP proxy");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['installedpackages']['miniupnpd']) && $config['installedpackages']['miniupnpd']['config'][0]['enable']) {
+ $pconfig = array();
+ $pconfig['name'] = "miniupnpd";
+ $pconfig['description'] = gettext("UPnP Service");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['installedpackages']['routed']) && $config['installedpackages']['routed']['config'][0]['enable']) {
+ $pconfig = array();
+ $pconfig['name'] = "routed";
+ $pconfig['description'] = gettext("RIP Daemon");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['ipsec']['enable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "ipsec";
+ $pconfig['description'] = gettext("IPsec VPN");
+ $services[] = $pconfig;
+ }
+
+ if (isset($config['system']['enablesshd'])) {
+ $pconfig = array();
+ $pconfig['name'] = "sshd";
+ $pconfig['description'] = gettext("Secure Shell Daemon");
+ $services[] = $pconfig;
+ }
+
+ foreach (array('server', 'client') as $mode) {
+ if (is_array($config['openvpn']["openvpn-{$mode}"])) {
+ foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
+ if (!isset($setting['disable'])) {
+ $pconfig = array();
+ $pconfig['name'] = "openvpn";
+ $pconfig['mode'] = $mode;
+ $pconfig['id'] = $id;
+ $pconfig['vpnid'] = $setting['vpnid'];
+ $pconfig['description'] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
+ $services[] = $pconfig;
+ }
+ }
+ }
+ }
+
+ if (count($config['load_balancer']['virtual_server']) && count($config['load_balancer']['lbpool'])) {
+ $pconfig = array();
+ $pconfig['name'] = "relayd";
+ $pconfig['description'] = gettext("Server load balancing daemon");
+ $services[] = $pconfig;
+ }
+ return $services;
+}
+
+function find_service_by_name($name) {
+ $services = get_services();
+ foreach ($services as $service) {
+ if ($service["name"] == $name) {
+ return $service;
+ }
+ }
+ return array();
+}
+
+function find_service_by_openvpn_vpnid($vpnid) {
+ $services = get_services();
+ foreach ($services as $service) {
+ if (($service["name"] == "openvpn") && isset($service["vpnid"]) && ($service["vpnid"] == $vpnid)) {
+ return $service;
+ }
+ }
+ return array();
+}
+
+function find_service_by_cp_zone($zone) {
+ $services = get_services();
+ foreach ($services as $service) {
+ if (($service["name"] == "captiveportal") && isset($service["zone"]) && ($service["zone"] == $zone)) {
+ return $service;
+ }
+ }
+ return array();
+}
+
+function service_name_compare($a, $b) {
+ if (strtolower($a['name']) == strtolower($b['name'])) {
+ return 0;
+ }
+ return (strtolower($a['name']) < strtolower($b['name'])) ? -1 : 1;
+}
+
+function get_pkg_descr($package_name) {
+ global $config;
+ if (is_array($config['installedpackages']['package'])) {
+ foreach ($config['installedpackages']['package'] as $pkg) {
+ if ($pkg['name'] == $package_name) {
+ return $pkg['descr'];
+ }
+ }
+ }
+ return gettext("Not available.");
+}
+
+function get_service_status($service) {
+ global $g;
+ switch ($service['name']) {
+ case "openvpn":
+ $running = is_pid_running("{$g['varrun_path']}/openvpn_{$service['mode']}{$service['vpnid']}.pid");
+ break;
+ case "captiveportal":
+ $running = is_pid_running("{$g['varrun_path']}/lighty-{$service['zone']}-CaptivePortal.pid");
+ if (isset($config['captiveportal'][$service['zone']]['httpslogin'])) {
+ $running = $running && is_pid_running("{$g['varrun_path']}/lighty-{$service['zone']}-CaptivePortal-SSL.pid");
+ }
+ break;
+ case "vhosts-http":
+ $running = is_pid_running("{$g['varrun_path']}/vhosts-http.pid");
+ break;
+ case "dhcrelay6":
+ $running = is_pid_running("{$g['varrun_path']}/dhcrelay6.pid");
+ break;
+ case 'ipsec':
+ $running = is_pid_running("{$g['varrun_path']}/charon.pid");
+ break;
+ default:
+ $running = is_service_running($service['name']);
+ }
+ return $running;
+}
+
+function get_service_status_icon($service, $withtext = true, $smallicon = false) {
+ global $g;
+ $output = "";
+ if (get_service_status($service)) {
+ $statustext = gettext("Running");
+ $output .= "<img style=\"vertical-align:middle\" title=\"" . sprintf(gettext("%s Service is"), $service["name"]) . " {$statustext}\" src=\"/themes/" . $g["theme"] . "/images/icons/";
+ $output .= ($smallicon) ? "icon_pass.gif" : "icon_service_running.gif";
+ $output .= "\" alt=\"status\" />&nbsp;";
+ if ($withtext) {
+ $output .= "&nbsp;" . $statustext;
+ }
+ } else {
+ $service_enabled = is_service_enabled($service['name']);
+ $statustext = ($service_enabled) ? gettext("Stopped") : gettext("Disabled");
+ $output .= "<img style=\"vertical-align:middle\" title=\"" . sprintf(gettext("%s Service is"), $service["name"]) . " {$statustext}\" src=\"/themes/" . $g["theme"] . "/images/icons/";
+ $output .= ($smallicon) ? "icon_block.gif" : "icon_service_stopped.gif";
+ $output .= "\" alt=\"status\" />&nbsp;";
+ if ($withtext) {
+ $output .= "&nbsp;<font color=\"white\">{$statustext}</font>";
+ }
+ }
+ return $output;
+}
+
+function get_service_control_links($service, $addname = false) {
+ global $g;
+ $output = "";
+ $stitle = ($addname) ? $service['name'] . " " : "";
+ if (get_service_status($service)) {
+ switch ($service['name']) {
+ case "openvpn":
+ $output .= "<a href='status_services.php?mode=restartservice&amp;service={$service['name']}&amp;vpnmode={$service['mode']}&amp;id={$service['vpnid']}'>";
+ break;
+ case "captiveportal":
+ $output .= "<a href='status_services.php?mode=restartservice&amp;service={$service['name']}&amp;zone={$service['zone']}'>";
+ break;
+ default:
+ $output .= "<a href='status_services.php?mode=restartservice&amp;service={$service['name']}'>";
+ }
+ $output .= "<img style=\"vertical-align:middle\" title='" . sprintf(gettext("Restart %sService"), $stitle) . "' border='0' src='/themes/".$g['theme']."/images/icons/icon_service_restart.gif' alt='restart' /></a>\n";
+ switch ($service['name']) {
+ case "openvpn":
+ $output .= "<a href='status_services.php?mode=stopservice&amp;service={$service['name']}&amp;vpnmode={$service['mode']}&amp;id={$service['vpnid']}'>";
+ break;
+ case "captiveportal":
+ $output .= "<a href='status_services.php?mode=stopservice&amp;service={$service['name']}&amp;zone={$service['zone']}'>";
+ break;
+ default:
+ $output .= "<a href='status_services.php?mode=stopservice&amp;service={$service['name']}'>";
+ }
+ $output .= "<img style=\"vertical-align:middle\" title='" . sprintf(gettext("Stop %sService"), $stitle) . "' border='0' src='/themes/".$g['theme']."/images/icons/icon_service_stop.gif' alt='stop' />";
+ $output .= "</a>";
+ } else {
+ $service_enabled = is_service_enabled($service['name']);
+ switch ($service['name']) {
+ case "openvpn":
+ $output .= "<a href='status_services.php?mode=startservice&amp;service={$service['name']}&amp;vpnmode={$service['mode']}&amp;id={$service['vpnid']}'>";
+ break;
+ case "captiveportal":
+ $output .= "<a href='status_services.php?mode=startservice&amp;service={$service['name']}&amp;zone={$service['zone']}'>";
+ break;
+ default:
+ if ($service_enabled) {
+ $output .= "<a href='status_services.php?mode=startservice&amp;service={$service['name']}'>";
+ }
+ }
+ if ($service_enabled) {
+ $output .= "<img style=\"vertical-align:middle\" title='" . sprintf(gettext("Start %sService"), $stitle) . "' border='0' src='/themes/".$g['theme']."/images/icons/icon_service_start.gif' alt='start' /></a>\n";
+ }
+ }
+ return $output;
+}
+
+function service_control_start($name, $extras) {
+ global $g;
+ switch ($name) {
+ case 'radvd':
+ services_radvd_configure();
+ break;
+ case 'captiveportal':
+ $zone = htmlspecialchars($extras['zone']);
+ captiveportal_init_webgui_zonename($zone);
+ break;
+ case 'ntpd':
+ case 'openntpd':
+ system_ntp_configure();
+ break;
+ case 'apinger':
+ setup_gateways_monitor();
+ break;
+ case 'bsnmpd':
+ services_snmpd_configure();
+ break;
+ case 'dhcrelay':
+ services_dhcrelay_configure();
+ break;
+ case 'dhcrelay6':
+ services_dhcrelay6_configure();
+ break;
+ case 'dnsmasq':
+ services_dnsmasq_configure();
+ break;
+ case 'unbound':
+ services_unbound_configure();
+ break;
+ case 'dhcpd':
+ services_dhcpd_configure();
+ break;
+ case 'igmpproxy':
+ services_igmpproxy_configure();
+ break;
+ case 'miniupnpd':
+ upnp_action('start');
+ break;
+ case 'ipsec':
+ vpn_ipsec_force_reload();
+ break;
+ case 'sshd':
+ send_event("service restart sshd");
+ break;
+ case 'openvpn':
+ $vpnmode = isset($extras['vpnmode']) ? htmlspecialchars($extras['vpnmode']) : htmlspecialchars($extras['mode']);
+ if (($vpnmode == "server") || ($vpnmode == "client")) {
+ $id = isset($extras['vpnid']) ? htmlspecialchars($extras['vpnid']) : htmlspecialchars($extras['id']);
+ $configfile = "{$g['varetc_path']}/openvpn/{$vpnmode}{$id}.conf";
+ if (file_exists($configfile)) {
+ openvpn_restart_by_vpnid($vpnmode, $id);
+ }
+ }
+ break;
+ case 'relayd':
+ relayd_configure();
+ break;
+ default:
+ start_service($name);
+ break;
+ }
+ return sprintf(gettext("%s has been started."), htmlspecialchars($name));
+}
+function service_control_stop($name, $extras) {
+ global $g;
+ switch ($name) {
+ case 'radvd':
+ killbypid("{$g['varrun_path']}/radvd.pid");
+ break;
+ case 'captiveportal':
+ $zone = htmlspecialchars($extras['zone']);
+ killbypid("{$g['varrun_path']}/lighty-{$zone}-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-{$zone}-CaptivePortal-SSL.pid");
+ break;
+ case 'ntpd':
+ killbyname("ntpd");
+ break;
+ case 'openntpd':
+ killbyname("openntpd");
+ break;
+ case 'apinger':
+ killbypid("{$g['varrun_path']}/apinger.pid");
+ break;
+ case 'bsnmpd':
+ killbypid("{$g['varrun_path']}/snmpd.pid");
+ break;
+ case 'choparp':
+ killbyname("choparp");
+ break;
+ case 'dhcpd':
+ killbyname("dhcpd");
+ break;
+ case 'dhcrelay':
+ killbypid("{$g['varrun_path']}/dhcrelay.pid");
+ break;
+ case 'dhcrelay6':
+ killbypid("{$g['varrun_path']}/dhcrelay6.pid");
+ break;
+ case 'dnsmasq':
+ killbypid("{$g['varrun_path']}/dnsmasq.pid");
+ break;
+ case 'unbound':
+ killbypid("{$g['varrun_path']}/unbound.pid");
+ break;
+ case 'igmpproxy':
+ killbyname("igmpproxy");
+ break;
+ case 'miniupnpd':
+ upnp_action('stop');
+ break;
+ case 'sshd':
+ killbyname("sshd");
+ break;
+ case 'ipsec':
+ exec("/usr/local/sbin/ipsec stop");
+ break;
+ case 'openvpn':
+ $vpnmode = htmlspecialchars($extras['vpnmode']);
+ if (($vpnmode == "server") or ($vpnmode == "client")) {
+ $id = htmlspecialchars($extras['id']);
+ $pidfile = "{$g['varrun_path']}/openvpn_{$vpnmode}{$id}.pid";
+ killbypid($pidfile);
+ }
+ break;
+ case 'relayd':
+ mwexec('pkill relayd');
+ break;
+ default:
+ stop_service($name);
+ break;
+ }
+ return sprintf(gettext("%s has been stopped."), htmlspecialchars($name));
+}
+
+function service_control_restart($name, $extras) {
+ global $g;
+ switch ($name) {
+ case 'radvd':
+ services_radvd_configure();
+ break;
+ case 'captiveportal':
+ $zone = htmlspecialchars($extras['zone']);
+ killbypid("{$g['varrun_path']}/lighty-{$zone}-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-{$zone}-CaptivePortal-SSL.pid");
+ captiveportal_init_webgui_zonename($zone);
+ break;
+ case 'ntpd':
+ case 'openntpd':
+ system_ntp_configure();
+ break;
+ case 'apinger':
+ killbypid("{$g['varrun_path']}/apinger.pid");
+ setup_gateways_monitor();
+ break;
+ case 'bsnmpd':
+ services_snmpd_configure();
+ break;
+ case 'dhcrelay':
+ services_dhcrelay_configure();
+ break;
+ case 'dhcrelay6':
+ services_dhcrelay6_configure();
+ break;
+ case 'dnsmasq':
+ services_dnsmasq_configure();
+ break;
+ case 'unbound':
+ services_unbound_configure();
+ break;
+ case 'dhcpd':
+ services_dhcpd_configure();
+ break;
+ case 'igmpproxy':
+ services_igmpproxy_configure();
+ break;
+ case 'miniupnpd':
+ upnp_action('restart');
+ break;
+ case 'ipsec':
+ vpn_ipsec_force_reload();
+ break;
+ case 'sshd':
+ send_event("service restart sshd");
+ break;
+ case 'openvpn':
+ $vpnmode = htmlspecialchars($extras['vpnmode']);
+ if ($vpnmode == "server" || $vpnmode == "client") {
+ $id = htmlspecialchars($extras['id']);
+ $configfile = "{$g['varetc_path']}/openvpn/{$vpnmode}{$id}.conf";
+ if (file_exists($configfile)) {
+ openvpn_restart_by_vpnid($vpnmode, $id);
+ }
+ }
+ break;
+ case 'relayd':
+ relayd_configure(true);
+ break;
+ default:
+ restart_service($name);
+ break;
+ }
+ return sprintf(gettext("%s has been restarted."), htmlspecialchars($name));
+}
+
+?>
diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc
new file mode 100644
index 0000000..c254c35
--- /dev/null
+++ b/src/etc/inc/services.inc
@@ -0,0 +1,2541 @@
+<?php
+/*
+ services.inc
+ part of the pfSense project (https://www.pfsense.org)
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2010 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/bin/killall /bin/pgrep /bin/sh /usr/local/sbin/dhcpd /usr/local/sbin/igmpproxy
+ pfSense_BUILDER_BINARIES: /sbin/ifconfig /usr/local/sbin/dnsmasq
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/miniupnpd /usr/sbin/radvd
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/dhcleases6 /usr/sbin/bsnmpd
+ pfSense_MODULE: utils
+*/
+
+define('DYNDNS_PROVIDER_VALUES', 'citynetwork cloudflare custom custom-v6 dhs dnsexit dnsimple dnsmadeeasy dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns glesys googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost zoneedit');
+define('DYNDNS_PROVIDER_DESCRIPTIONS', 'City Network,CloudFlare,Custom,Custom (v6),DHS,DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,GleSYS,Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,ZoneEdit');
+
+/* implement ipv6 route advertising daemon */
+function services_radvd_configure($blacklist = array()) {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_radvd_configure() being called $mt\n";
+ }
+
+ if (!is_array($config['dhcpdv6'])) {
+ $config['dhcpdv6'] = array();
+ }
+
+ $Iflist = get_configured_interface_list();
+ $Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
+ $carplist = get_configured_carp_interface_list();
+
+ $radvdconf = "# Automatically Generated, do not edit\n";
+
+ /* Process all links which need the router advertise daemon */
+ $radvdifs = array();
+
+ /* handle manually configured DHCP6 server settings first */
+ foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
+ if (!is_array($config['interfaces'][$dhcpv6if])) {
+ continue;
+ }
+ if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
+ continue;
+ }
+
+ /* Do not put in the config an interface which is down */
+ if (isset($blacklist[$dhcpv6if])) {
+ continue;
+ }
+ if (!isset($dhcpv6ifconf['ramode'])) {
+ $dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
+ }
+
+ /* are router advertisements enabled? */
+ if ($dhcpv6ifconf['ramode'] == "disabled") {
+ continue;
+ }
+
+ if (!isset($dhcpv6ifconf['rapriority'])) {
+ $dhcpv6ifconf['rapriority'] = "medium";
+ }
+
+ /* always start with the real parent, we override with the carp if later */
+ $carpif = false;
+ /* check if we need to listen on a CARP interface */
+ if (!empty($dhcpv6ifconf['rainterface'])) {
+ if (!empty($carplist[$dhcpv6ifconf['rainterface']])) {
+ $dhcpv6if = $dhcpv6ifconf['rainterface'];
+ $carpif = true;
+ }
+ }
+
+ if (strstr($dhcpv6if, "_vip")) {
+ // CARP IP, check if it's enabled and find parent
+ if (!get_carp_status() || get_carp_interface_status($dhcpv6if) != "MASTER") {
+ continue;
+ }
+ $ifparent = link_carp_interface_to_parent($dhcpv6if);
+ $realif = convert_friendly_interface_to_real_interface_name($ifparent);
+ } else {
+ $realif = get_real_interface($dhcpv6if, "inet6");
+ }
+
+ if (isset($radvdifs[$realif])) {
+ continue;
+ }
+
+ $ifcfgipv6 = get_interface_ipv6($dhcpv6if);
+ if (!is_ipaddrv6($ifcfgipv6)) {
+ continue;
+ }
+
+ $ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
+ $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
+ $radvdifs[$realif] = $realif;
+
+ $radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
+ $radvdconf .= "interface {$realif} {\n";
+ if (strstr($realif, "ovpn")) {
+ $radvdconf .= "\tUnicastOnly on;\n";
+ }
+ $radvdconf .= "\tAdvSendAdvert on;\n";
+ $radvdconf .= "\tMinRtrAdvInterval 5;\n";
+ $radvdconf .= "\tMaxRtrAdvInterval 20;\n";
+ $mtu = get_interface_mtu($realif);
+ if (is_numeric($mtu)) {
+ $radvdconf .= "\tAdvLinkMTU {$mtu};\n";
+ } else {
+ $radvdconf .= "\tAdvLinkMTU 1280;\n";
+ }
+ // $radvdconf .= "\tDeprecatePrefix on;\n";
+ switch ($dhcpv6ifconf['rapriority']) {
+ case "low":
+ $radvdconf .= "\tAdvDefaultPreference low;\n";
+ break;
+ case "high":
+ $radvdconf .= "\tAdvDefaultPreference high;\n";
+ break;
+ default:
+ $radvdconf .= "\tAdvDefaultPreference medium;\n";
+ break;
+ }
+ switch ($dhcpv6ifconf['ramode']) {
+ case "managed":
+ case "assist":
+ $radvdconf .= "\tAdvManagedFlag on;\n";
+ $radvdconf .= "\tAdvOtherConfigFlag on;\n";
+ break;
+ case "stateless_dhcp":
+ $radvdconf .= "\tAdvManagedFlag off;\n";
+ $radvdconf .= "\tAdvOtherConfigFlag on;\n";
+ break;
+ }
+ $radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
+ if ($carpif == true) {
+ $radvdconf .= "\t\tDeprecatePrefix off;\n";
+ } else {
+ $radvdconf .= "\t\tDeprecatePrefix on;\n";
+ }
+ switch ($dhcpv6ifconf['ramode']) {
+ case "managed":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous off;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "router":
+ $radvdconf .= "\t\tAdvOnLink off;\n";
+ $radvdconf .= "\t\tAdvAutonomous off;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "stateless_dhcp":
+ case "assist":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous on;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "unmanaged":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous on;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ }
+ $radvdconf .= "\t};\n";
+
+ if (is_array($dhcpv6ifconf['subnets']['item'])) {
+ foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
+ if (is_subnetv6($subnet)) {
+ $radvdconf .= "\tprefix {$subnet} {\n";
+ if ($carpif == true) {
+ $radvdconf .= "\t\tDeprecatePrefix off;\n";
+ } else {
+ $radvdconf .= "\t\tDeprecatePrefix on;\n";
+ }
+ switch ($dhcpv6ifconf['ramode']) {
+ case "managed":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous off;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "router":
+ $radvdconf .= "\t\tAdvOnLink off;\n";
+ $radvdconf .= "\t\tAdvAutonomous off;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "assist":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous on;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ case "unmanaged":
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous on;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ break;
+ }
+ $radvdconf .= "\t};\n";
+ }
+ }
+ }
+ if ($carpif === true) {
+ $radvdconf .= "\troute ::/0 {\n";
+ $radvdconf .= "\t\tRemoveRoute off;\n";
+ $radvdconf .= "\t};\n";
+ } else {
+ $radvdconf .= "\troute ::/0 {\n";
+ $radvdconf .= "\t\tRemoveRoute on;\n";
+ $radvdconf .= "\t};\n";
+ }
+
+ /* add DNS servers */
+ $dnslist = array();
+ if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
+ foreach ($dhcpv6ifconf['dnsserver'] as $server) {
+ if (is_ipaddrv6($server)) {
+ $dnslist[] = $server;
+ }
+ }
+ } elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
+ foreach ($dhcpv6ifconf['radnsserver'] as $server) {
+ if (is_ipaddrv6($server)) {
+ $dnslist[] = $server;
+ }
+ }
+ } elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
+ $dnslist[] = get_interface_ipv6($realif);
+ } elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
+ foreach ($config['system']['dnsserver'] as $server) {
+ if (is_ipaddrv6($server)) {
+ $dnslist[] = $server;
+ }
+ }
+ }
+ if (count($dnslist) > 0) {
+ $dnsstring = implode(" ", $dnslist);
+ if ($dnsstring <> "") {
+ $radvdconf .= "\tRDNSS {$dnsstring} { };\n";
+ }
+ }
+ if (!empty($dhcpv6ifconf['domain'])) {
+ $radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
+ } elseif (!empty($config['system']['domain'])) {
+ $radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
+ }
+ $radvdconf .= "};\n";
+ }
+
+ /* handle DHCP-PD prefixes and 6RD dynamic interfaces */
+ foreach ($Iflist as $if => $ifdescr) {
+ if (!isset($config['interfaces'][$if]['track6-interface'])) {
+ continue;
+ }
+ if (!isset($config['interfaces'][$if]['enable'])) {
+ continue;
+ }
+ /* Do not put in the config an interface which is down */
+ if (isset($blacklist[$if])) {
+ continue;
+ }
+ $trackif = $config['interfaces'][$if]['track6-interface'];
+ if (empty($config['interfaces'][$trackif])) {
+ continue;
+ }
+
+ if (strstr($if, "_vip")) {
+ // CARP IP, find parent
+ $ifparent = link_carp_interface_to_parent($if);
+ $realif = convert_friendly_interface_to_real_interface_name($ifparent);
+ } else {
+ $realif = get_real_interface($if, "inet6");
+ }
+
+ /* prevent duplicate entries, manual overrides */
+ if (isset($radvdifs[$realif])) {
+ continue;
+ }
+
+ $ifcfgipv6 = get_interface_ipv6($if);
+ if (!is_ipaddrv6($ifcfgipv6)) {
+ $subnetv6 = "::";
+ $ifcfgsnv6 = "64";
+ } else {
+ $ifcfgsnv6 = get_interface_subnetv6($if);
+ $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
+ }
+ $radvdifs[$realif] = $realif;
+
+ $autotype = $config['interfaces'][$trackif]['ipaddrv6'];
+
+ if ($g['debug']) {
+ log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
+ }
+
+ $radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
+ $radvdconf .= "interface {$realif} {\n";
+ $radvdconf .= "\tAdvSendAdvert on;\n";
+ $radvdconf .= "\tMinRtrAdvInterval 3;\n";
+ $radvdconf .= "\tMaxRtrAdvInterval 10;\n";
+ $mtu = get_interface_mtu($realif);
+ if (is_numeric($mtu)) {
+ $radvdconf .= "\tAdvLinkMTU {$mtu};\n";
+ } else {
+ $radvdconf .= "\tAdvLinkMTU 1280;\n";
+ }
+ $radvdconf .= "\tAdvOtherConfigFlag on;\n";
+ $radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
+ $radvdconf .= "\t\tAdvOnLink on;\n";
+ $radvdconf .= "\t\tAdvAutonomous on;\n";
+ $radvdconf .= "\t\tAdvRouterAddr on;\n";
+ $radvdconf .= "\t};\n";
+
+ /* add DNS servers */
+ $dnslist = array();
+ if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
+ $dnslist[] = $ifcfgipv6;
+ } elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
+ foreach ($config['system']['dnsserver'] as $server) {
+ if (is_ipaddrv6($server)) {
+ $dnslist[] = $server;
+ }
+ }
+ }
+ if (count($dnslist) > 0) {
+ $dnsstring = implode(" ", $dnslist);
+ if (!empty($dnsstring)) {
+ $radvdconf .= "\tRDNSS {$dnsstring} { };\n";
+ }
+ }
+ if (!empty($config['system']['domain'])) {
+ $radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
+ }
+ $radvdconf .= "};\n";
+ }
+
+ /* write radvd.conf */
+ if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
+ log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
+ if (platform_booting()) {
+ printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
+ }
+ }
+ unset($radvdconf);
+
+ if (count($radvdifs) > 0) {
+ if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
+ sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
+ } else {
+ mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
+ }
+ } else {
+ /* we need to shut down the radvd cleanly, it will send out the prefix
+ * information with a lifetime of 0 to notify clients of a (possible) new prefix */
+ if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
+ log_error("Shutting down Router Advertisment daemon cleanly");
+ killbypid("{$g['varrun_path']}/radvd.pid");
+ @unlink("{$g['varrun_path']}/radvd.pid");
+ }
+ }
+ return 0;
+}
+
+function services_dhcpd_configure($family = "all", $blacklist = array()) {
+ global $config, $g;
+
+ /* configure DHCPD chroot once */
+ $fd = fopen("{$g['tmp_path']}/dhcpd.sh", "w");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
+ fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
+ fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
+ fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
+ fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
+ fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
+
+ $status = `/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep "{$g['dhcpd_chroot_path']}/dev"`;
+ if (!trim($status)) {
+ fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
+ }
+ fclose($fd);
+ mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
+
+ if ($family == "all" || $family == "inet") {
+ services_dhcpdv4_configure();
+ }
+ if ($family == "all" || $family == "inet6") {
+ services_dhcpdv6_configure($blacklist);
+ services_radvd_configure($blacklist);
+ }
+}
+
+function services_dhcpdv4_configure() {
+ global $config, $g;
+ $need_ddns_updates = false;
+ $ddns_zones = array();
+
+ if ($g['services_dhcp_server_enable'] == false) {
+ return;
+ }
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dhcpdv4_configure($if) being called $mt\n";
+ }
+
+ /* kill any running dhcpd */
+ if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
+ killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
+ }
+
+ /* DHCP enabled on any interfaces? */
+ if (!is_dhcp_server_enabled()) {
+ return 0;
+ }
+
+ /* if OLSRD is enabled, allow WAN to house DHCP. */
+ if (!function_exists('is_package_installed')) {
+ require_once('pkg-utils.inc');
+ }
+ if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) {
+ foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
+ if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
+ $is_olsr_enabled = true;
+ break;
+ }
+ }
+ }
+
+ if (platform_booting()) {
+ /* restore the leases, if we have them */
+ if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
+ $dhcprestore = "";
+ $dhcpreturn = "";
+ exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
+ $dhcprestore = implode(" ", $dhcprestore);
+ if ($dhcpreturn <> 0) {
+ log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
+ }
+ }
+ /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
+ if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
+ unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
+ }
+ }
+
+ $syscfg = $config['system'];
+ if (!is_array($config['dhcpd'])) {
+ $config['dhcpd'] = array();
+ }
+ $dhcpdcfg = $config['dhcpd'];
+ $Iflist = get_configured_interface_list();
+
+ /* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
+ $dns_arrv4 = array();
+ if (is_array($syscfg['dnsserver'])) {
+ foreach ($syscfg['dnsserver'] as $dnsserver) {
+ if (is_ipaddrv4($dnsserver)) {
+ $dns_arrv4[] = $dnsserver;
+ }
+ }
+ }
+
+ if (platform_booting()) {
+ echo gettext("Starting DHCP service...");
+ } else {
+ sleep(1);
+ }
+
+ $custoptions = "";
+ foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
+ if (is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
+ foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
+ if (!empty($item['type'])) {
+ $itemtype = $item['type'];
+ } else {
+ $itemtype = "text";
+ }
+ $custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
+ }
+ }
+ }
+
+ $dhcpdconf = <<<EOD
+
+option domain-name "{$syscfg['domain']}";
+option ldap-server code 95 = text;
+option domain-search-list code 119 = text;
+option arch code 93 = unsigned integer 16; # RFC4578
+{$custoptions}
+default-lease-time 7200;
+max-lease-time 86400;
+log-facility local7;
+one-lease-per-client true;
+deny duplicates;
+ping-check true;
+update-conflict-detection false;
+
+EOD;
+
+ if (!isset($dhcpifconf['disableauthoritative'])) {
+ $dhcpdconf .= "authoritative;\n";
+ }
+
+ if (isset($dhcpifconf['alwaysbroadcast'])) {
+ $dhcpdconf .= "always-broadcast on\n";
+ }
+
+ $dhcpdifs = array();
+ $enable_add_routers = false;
+ $gateways_arr = return_gateways_array();
+ /* only add a routers line if the system has any IPv4 gateway at all */
+ /* a static route has a gateway, manually overriding this field always works */
+ foreach ($gateways_arr as $gwitem) {
+ if ($gwitem['ipprotocol'] == "inet") {
+ $enable_add_routers = true;
+ break;
+ }
+ }
+
+ /* loop through and determine if we need to setup
+ * failover peer "bleh" entries
+ */
+ foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
+
+ if (!isset($config['interfaces'][$dhcpif]['enable'])) {
+ continue;
+ }
+
+ interfaces_staticarp_configure($dhcpif);
+
+ if (!isset($dhcpifconf['enable'])) {
+ continue;
+ }
+
+ if ($dhcpifconf['failover_peerip'] <> "") {
+ $intip = get_interface_ip($dhcpif);
+ /*
+ * yep, failover peer is defined.
+ * does it match up to a defined vip?
+ */
+ $skew = 110;
+ if (is_array($config['virtualip']['vip'])) {
+ foreach ($config['virtualip']['vip'] as $vipent) {
+ if ($vipent['interface'] == $dhcpif) {
+ $carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
+ if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
+ /* this is the interface! */
+ if (is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
+ $skew = 0;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ log_error(gettext("Warning! DHCP Failover setup and no CARP virtual IPs defined!"));
+ }
+ if ($skew > 10) {
+ $type = "secondary";
+ $my_port = "520";
+ $peer_port = "519";
+ } else {
+ $my_port = "519";
+ $peer_port = "520";
+ $type = "primary";
+ $dhcpdconf_pri = "split 128;\n";
+ $dhcpdconf_pri .= " mclt 600;\n";
+ }
+
+ if (is_ipaddrv4($intip)) {
+ $dhcpdconf .= <<<EOPP
+failover peer "dhcp_{$dhcpif}" {
+ {$type};
+ address {$intip};
+ port {$my_port};
+ peer address {$dhcpifconf['failover_peerip']};
+ peer port {$peer_port};
+ max-response-delay 10;
+ max-unacked-updates 10;
+ {$dhcpdconf_pri}
+ load balance max seconds 3;
+}
+\n
+EOPP;
+ }
+ }
+ }
+
+ foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
+
+ $newzone = array();
+ $ifcfg = $config['interfaces'][$dhcpif];
+
+ if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) {
+ continue;
+ }
+ $ifcfgip = get_interface_ip($dhcpif);
+ $ifcfgsn = get_interface_subnet($dhcpif);
+ $subnet = gen_subnet($ifcfgip, $ifcfgsn);
+ $subnetmask = gen_subnet_mask($ifcfgsn);
+
+ if (!is_ipaddr($subnet)) {
+ continue;
+ }
+
+ if ($is_olsr_enabled == true) {
+ if ($dhcpifconf['netmask']) {
+ $subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
+ }
+ }
+
+ $all_pools = array();
+ $all_pools[] = $dhcpifconf;
+ if (is_array($dhcpifconf['pool'])) {
+ $all_pools = array_merge($all_pools, $dhcpifconf['pool']);
+ }
+
+ $dnscfg = "";
+
+ if ($dhcpifconf['domain']) {
+ $dnscfg .= " option domain-name \"{$dhcpifconf['domain']}\";\n";
+ }
+
+ if ($dhcpifconf['domainsearchlist'] <> "") {
+ $dnscfg .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
+ }
+
+ if (isset($dhcpifconf['ddnsupdate'])) {
+ $need_ddns_updates = true;
+ $newzone = array();
+ if ($dhcpifconf['ddnsdomain'] <> "") {
+ $newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
+ $dnscfg .= " ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
+ } else {
+ $newzone['domain-name'] = $config['system']['domain'];
+ }
+ $revsubnet = explode(".", $subnet);
+ $revsubnet = array_reverse($revsubnet);
+ foreach ($revsubnet as $octet) {
+ if ($octet != "0") {
+ break;
+ }
+ array_shift($revsubnet);
+ }
+ $newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
+ }
+
+ if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
+ $dnscfg .= " option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
+ if ($newzone['domain-name']) {
+ $newzone['dns-servers'] = $dhcpifconf['dnsserver'];
+ }
+ } else if (isset($config['dnsmasq']['enable'])) {
+ $dnscfg .= " option domain-name-servers {$ifcfgip};";
+ if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
+ $newzone['dns-servers'] = $syscfg['dnsserver'];
+ }
+ } else if (isset($config['unbound']['enable'])) {
+ $dnscfg .= " option domain-name-servers {$ifcfgip};";
+ } else if (!empty($dns_arrv4)) {
+ $dnscfg .= " option domain-name-servers " . join(",", $dns_arrv4) . ";";
+ if ($newzone['domain-name']) {
+ $newzone['dns-servers'] = $dns_arrv4;
+ }
+ }
+
+ /* Create classes - These all contain comma separated lists. Join them into one
+ big comma separated string then split them all up. */
+ $all_mac_strings = array();
+ if (is_array($dhcpifconf['pool'])) {
+ foreach ($all_pools as $poolconf) {
+ $all_mac_strings[] = $poolconf['mac_allow'];
+ $all_mac_strings[] = $poolconf['mac_deny'];
+ }
+ }
+ $all_mac_strings[] = $dhcpifconf['mac_allow'];
+ $all_mac_strings[] = $dhcpifconf['mac_deny'];
+ if (!empty($all_mac_strings)) {
+ $all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
+ foreach ($all_mac_list as $mac) {
+ if (empty($mac)) {
+ continue;
+ }
+ $dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
+ // Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
+ $dhcpdconf .= ' match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
+ $dhcpdconf .= '}' . "\n";
+ }
+ }
+
+ $dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
+
+ // Setup pool options
+ foreach ($all_pools as $poolconf) {
+ $dhcpdconf .= " pool {\n";
+ /* is failover dns setup? */
+ if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
+ $dhcpdconf .= " option domain-name-servers {$poolconf['dnsserver'][0]}";
+ if ($poolconf['dnsserver'][1] <> "") {
+ $dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
+ }
+ if ($poolconf['dnsserver'][2] <> "") {
+ $dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
+ }
+ if ($poolconf['dnsserver'][3] <> "") {
+ $dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
+ }
+ $dhcpdconf .= ";\n";
+ }
+
+ /* allow/deny MACs */
+ $mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
+ foreach ($mac_allow_list as $mac) {
+ if (empty($mac)) {
+ continue;
+ }
+ $dhcpdconf .= " allow members of \"" . str_replace(':', '', $mac) . "\";\n";
+ }
+ $mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
+ foreach ($mac_deny_list as $mac) {
+ if (empty($mac)) {
+ continue;
+ }
+ $dhcpdconf .= " deny members of \"" . str_replace(':', '', $mac) . "\";\n";
+ }
+
+ if ($poolconf['failover_peerip'] <> "") {
+ $dhcpdconf .= " deny dynamic bootp clients;\n";
+ }
+
+ if (isset($poolconf['denyunknown'])) {
+ $dhcpdconf .= " deny unknown-clients;\n";
+ }
+
+ if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
+ $dhcpdconf .= " option routers {$poolconf['gateway']};\n";
+ }
+
+ if ($dhcpifconf['failover_peerip'] <> "") {
+ $dhcpdconf .= " failover peer \"dhcp_{$dhcpif}\";\n";
+ }
+
+ $pdnscfg = "";
+
+ if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
+ $pdnscfg .= " option domain-name \"{$poolconf['domain']}\";\n";
+ }
+
+ if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
+ $pdnscfg .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
+ }
+
+ if (isset($poolconf['ddnsupdate'])) {
+ if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
+ $pdnscfg .= " ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
+ }
+ $pdnscfg .= " ddns-update-style interim;\n";
+ }
+
+ if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
+ $pdnscfg .= " option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
+ }
+ $dhcpdconf .= "{$pdnscfg}";
+
+ // default-lease-time
+ if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
+ $dhcpdconf .= " default-lease-time {$poolconf['defaultleasetime']};\n";
+ }
+
+ // max-lease-time
+ if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
+ $dhcpdconf .= " max-lease-time {$poolconf['maxleasetime']};\n";
+ }
+
+ // netbios-name*
+ if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
+ $dhcpdconf .= " option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
+ $dhcpdconf .= " option netbios-node-type 8;\n";
+ }
+
+ // ntp-servers
+ if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
+ $dhcpdconf .= " option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
+ }
+
+ // tftp-server-name
+ if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
+ $dhcpdconf .= " option tftp-server-name \"{$poolconf['tftp']}\";\n";
+ }
+
+ // ldap-server
+ if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
+ $dhcpdconf .= " option ldap-server \"{$poolconf['ldap']}\";\n";
+ }
+
+ // net boot information
+ if (isset($poolconf['netboot'])) {
+ if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
+ $dhcpdconf .= " next-server {$poolconf['nextserver']};\n";
+ }
+ if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
+ $dhcpdconf .= " filename \"{$poolconf['filename']}\";\n";
+ }
+ if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
+ $dhcpdconf .= " option root-path \"{$poolconf['rootpath']}\";\n";
+ }
+ }
+ $dhcpdconf .= " range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
+ $dhcpdconf .= " }\n\n";
+ }
+// End of settings inside pools
+
+ if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
+ $routers = $dhcpifconf['gateway'];
+ $add_routers = true;
+ } elseif ($dhcpifconf['gateway'] == "none") {
+ $add_routers = false;
+ } else {
+ $add_routers = $enable_add_routers;
+ $routers = $ifcfgip;
+ }
+ if ($add_routers) {
+ $dhcpdconf .= " option routers {$routers};\n";
+ }
+
+ $dhcpdconf .= <<<EOD
+$dnscfg
+
+EOD;
+ // default-lease-time
+ if ($dhcpifconf['defaultleasetime']) {
+ $dhcpdconf .= " default-lease-time {$dhcpifconf['defaultleasetime']};\n";
+ }
+
+ // max-lease-time
+ if ($dhcpifconf['maxleasetime']) {
+ $dhcpdconf .= " max-lease-time {$dhcpifconf['maxleasetime']};\n";
+ }
+
+ // netbios-name*
+ if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
+ $dhcpdconf .= " option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
+ $dhcpdconf .= " option netbios-node-type 8;\n";
+ }
+
+ // ntp-servers
+ if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0]) {
+ $dhcpdconf .= " option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
+ }
+
+ // tftp-server-name
+ if ($dhcpifconf['tftp'] <> "") {
+ $dhcpdconf .= " option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
+ }
+
+ // Handle option, number rowhelper values
+ $dhcpdconf .= "\n";
+ if ($dhcpifconf['numberoptions']['item']) {
+ foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
+ if (empty($item['type']) || $item['type'] == "text") {
+ $dhcpdconf .= " option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
+ } else {
+ $dhcpdconf .= " option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
+ }
+ }
+ }
+
+ // ldap-server
+ if ($dhcpifconf['ldap'] <> "") {
+ $dhcpdconf .= " option ldap-server \"{$dhcpifconf['ldap']}\";\n";
+ }
+
+ // net boot information
+ if (isset($dhcpifconf['netboot'])) {
+ if ($dhcpifconf['nextserver'] <> "") {
+ $dhcpdconf .= " next-server {$dhcpifconf['nextserver']};\n";
+ }
+ if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
+ $dhcpdconf .= " if option arch = 00:06 {\n";
+ $dhcpdconf .= " filename \"{$dhcpifconf['filename32']}\";\n";
+ $dhcpdconf .= " } else if option arch = 00:07 {\n";
+ $dhcpdconf .= " filename \"{$dhcpifconf['filename64']}\";\n";
+ $dhcpdconf .= " } else {\n";
+ $dhcpdconf .= " filename \"{$dhcpifconf['filename']}\";\n";
+ $dhcpdconf .= " }\n\n";
+ } elseif (!empty($dhcpifconf['filename'])) {
+ $dhcpdconf .= " filename \"{$dhcpifconf['filename']}\";\n";
+ }
+ if (!empty($dhcpifconf['rootpath'])) {
+ $dhcpdconf .= " option root-path \"{$dhcpifconf['rootpath']}\";\n";
+ }
+ }
+
+ $dhcpdconf .= <<<EOD
+}
+
+EOD;
+
+ /* add static mappings */
+ if (is_array($dhcpifconf['staticmap'])) {
+
+ $i = 0;
+ foreach ($dhcpifconf['staticmap'] as $sm) {
+ $dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
+
+ if ($sm['mac']) {
+ $dhcpdconf .= " hardware ethernet {$sm['mac']};\n";
+ }
+
+ if ($sm['cid']) {
+ $dhcpdconf .= " option dhcp-client-identifier \"{$sm['cid']}\";\n";
+ }
+
+ if ($sm['ipaddr']) {
+ $dhcpdconf .= " fixed-address {$sm['ipaddr']};\n";
+ }
+
+ if ($sm['hostname']) {
+ $dhhostname = str_replace(" ", "_", $sm['hostname']);
+ $dhhostname = str_replace(".", "_", $dhhostname);
+ $dhcpdconf .= " option host-name \"{$dhhostname}\";\n";
+ }
+ if ($sm['filename']) {
+ $dhcpdconf .= " filename \"{$sm['filename']}\";\n";
+ }
+
+ if ($sm['rootpath']) {
+ $dhcpdconf .= " option root-path \"{$sm['rootpath']}\";\n";
+ }
+
+ if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
+ $dhcpdconf .= " option routers {$sm['gateway']};\n";
+ }
+
+ $smdnscfg = "";
+
+ if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
+ $smdnscfg .= " option domain-name \"{$sm['domain']}\";\n";
+ }
+
+ if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
+ $smdnscfg .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
+ }
+
+ if (isset($sm['ddnsupdate'])) {
+ if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
+ $pdnscfg .= " ddns-domainname \"{$sm['ddnsdomain']}\";\n";
+ }
+ $pdnscfg .= " ddns-update-style interim;\n";
+ }
+
+ if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
+ $smdnscfg .= " option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
+ }
+ $dhcpdconf .= "{$smdnscfg}";
+
+ // default-lease-time
+ if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
+ $dhcpdconf .= " default-lease-time {$sm['defaultleasetime']};\n";
+ }
+
+ // max-lease-time
+ if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
+ $dhcpdconf .= " max-lease-time {$sm['maxleasetime']};\n";
+ }
+
+ // netbios-name*
+ if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
+ $dhcpdconf .= " option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
+ $dhcpdconf .= " option netbios-node-type 8;\n";
+ }
+
+ // ntp-servers
+ if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
+ $dhcpdconf .= " option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
+ }
+
+ // tftp-server-name
+ if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
+ $dhcpdconf .= " option tftp-server-name \"{$sm['tftp']}\";\n";
+ }
+
+ $dhcpdconf .= "}\n";
+ $i++;
+ }
+ }
+
+ $dhcpdifs[] = get_real_interface($dhcpif);
+ if ($newzone['domain-name']) {
+ if ($need_ddns_updates) {
+ $newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
+ }
+ $ddns_zones[] = $newzone;
+ }
+ }
+
+ if ($need_ddns_updates) {
+ $dhcpdconf .= "ddns-update-style interim;\n";
+ $dhcpdconf .= "update-static-leases on;\n";
+
+ $dhcpdconf .= dhcpdkey($dhcpifconf);
+ $dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
+ }
+
+ /* write dhcpd.conf */
+ if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
+ printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
+ unset($dhcpdconf);
+ return 1;
+ }
+ unset($dhcpdconf);
+
+ /* create an empty leases database */
+ if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
+ @touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
+ }
+
+ /* make sure there isn't a stale dhcpd.pid file, which can make dhcpd fail to start. */
+ /* if we get here, dhcpd has been killed and is not started yet */
+ unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
+
+ /* fire up dhcpd in a chroot */
+ if (count($dhcpdifs) > 0) {
+ mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
+ join(" ", $dhcpdifs));
+ }
+
+ if (platform_booting()) {
+ print "done.\n";
+ }
+
+ return 0;
+}
+
+function dhcpdkey($dhcpifconf) {
+ $dhcpdconf = "";
+ if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
+ $dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
+ $dhcpdconf .= " algorithm hmac-md5;\n";
+ $dhcpdconf .= " secret {$dhcpifconf['ddnsdomainkey']};\n";
+ $dhcpdconf .= "}\n";
+ }
+
+ return $dhcpdconf;
+}
+
+function dhcpdzones($ddns_zones, $dhcpifconf) {
+ $dhcpdconf = "";
+
+ if (is_array($ddns_zones)) {
+ $added_zones = array();
+ foreach ($ddns_zones as $zone) {
+ if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
+ continue;
+ }
+ $primary = $zone['dns-servers'][0];
+ $secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
+
+ // Make sure we aren't using any invalid or IPv6 DNS servers.
+ if (!is_ipaddrv4($primary)) {
+ if (is_ipaddrv4($secondary)) {
+ $primary = $secondary;
+ $secondary = "";
+ } else {
+ continue;
+ }
+ }
+
+ // We don't need to add zones multiple times.
+ if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
+ $dhcpdconf .= "zone {$zone['domain-name']}. {\n";
+ $dhcpdconf .= " primary {$primary};\n";
+ if (is_ipaddrv4($secondary)) {
+ $dhcpdconf .= " secondary {$secondary};\n";
+ }
+ if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
+ $dhcpdconf .= " key {$dhcpifconf['ddnsdomainkeyname']};\n";
+ }
+ $dhcpdconf .= "}\n";
+ $added_zones[] = $zone['domain-name'];
+ }
+ if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
+ $dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
+ $dhcpdconf .= " primary {$primary};\n";
+ if (is_ipaddrv4($secondary)) {
+ $dhcpdconf .= " secondary {$secondary};\n";
+ }
+ if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
+ $dhcpdconf .= " key {$dhcpifconf['ddnsdomainkeyname']};\n";
+ }
+ $dhcpdconf .= "}\n";
+ $added_zones[] = $zone['ptr-domain'];
+ }
+ }
+ }
+
+ return $dhcpdconf;
+}
+
+function services_dhcpdv6_configure($blacklist = array()) {
+ global $config, $g;
+
+ if ($g['services_dhcp_server_enable'] == false) {
+ return;
+ }
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dhcpd_configure($if) being called $mt\n";
+ }
+
+ /* kill any running dhcpd */
+ if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
+ killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
+ }
+ if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
+ killbypid("{$g['varrun_path']}/dhcpleases6.pid");
+ }
+
+ /* DHCP enabled on any interfaces? */
+ if (!is_dhcpv6_server_enabled()) {
+ return 0;
+ }
+
+ if (platform_booting()) {
+ if ($g['platform'] != "pfSense") {
+ /* restore the leases, if we have them */
+ if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
+ $dhcprestore = "";
+ $dhcpreturn = "";
+ exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
+ $dhcprestore = implode(" ", $dhcprestore);
+ if ($dhcpreturn <> 0) {
+ log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
+ }
+ }
+ }
+ }
+
+ $syscfg = $config['system'];
+ if (!is_array($config['dhcpdv6'])) {
+ $config['dhcpdv6'] = array();
+ }
+ $dhcpdv6cfg = $config['dhcpdv6'];
+ $Iflist = get_configured_interface_list();
+ $Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
+
+
+ if (platform_booting()) {
+ echo "Starting DHCPv6 service...";
+ } else {
+ sleep(1);
+ }
+
+ /* we add a fake entry for interfaces that are set to track6 another WAN */
+ foreach ($Iflist as $ifname) {
+ /* Do not put in the config an interface which is down */
+ if (isset($blacklist[$ifname])) {
+ continue;
+ }
+ if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
+ $realif = get_real_interface($ifname, "inet6");
+ $ifcfgipv6 = get_interface_ipv6($ifname);
+ if (!is_ipaddrv6($ifcfgipv6)) {
+ continue;
+ }
+ $ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
+ $trackifname = $config['interfaces'][$ifname]['track6-interface'];
+ $trackcfg = $config['interfaces'][$trackifname];
+ $pdlen = calculate_ipv6_delegation_length($trackifname);
+ $ifcfgipv6arr =explode(":", $ifcfgipv6);
+ $dhcpdv6cfg[$ifname] = array();
+ $dhcpdv6cfg[$ifname]['enable'] = true;
+ /* range */
+ $ifcfgipv6arr[7] = "1000";
+ $dhcpdv6cfg[$ifname]['range'] = array();
+ $dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
+ $ifcfgipv6arr[7] = "2000";
+ $dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
+ /* prefix length > 0? We can add dhcp6 prefix delegation server */
+ if ($pdlen > 2) {
+ $pdlenmax = $pdlen;
+ $pdlenhalf = $pdlenmax -1;
+ $pdlenmin = (64 - ceil($pdlenhalf / 4));
+ $dhcpdv6cfg[$ifname]['prefixrange'] = array();
+ $dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
+
+ /* set the delegation start to half the current address block */
+ $range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
+ $range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
+
+ /* set the end range to a multiple of the prefix delegation size, required by dhcpd */
+ $range = Net_IPv6::parseAddress($range['end'], (64 - $pdlenhalf));
+ $range['end'] = Net_IPv6::getNetmask($range['end'], (64 - round($pdlen / 2)));
+
+ $dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
+ $dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
+ }
+ $dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
+ }
+ }
+
+ $custoptionsv6 = "";
+ foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
+ if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
+ foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
+ $custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
+ }
+ }
+ }
+
+ if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
+ $custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
+ }
+
+ $dhcpdv6conf = <<<EOD
+
+option domain-name "{$syscfg['domain']}";
+option ldap-server code 95 = text;
+option domain-search-list code 119 = text;
+{$custoptionsv6}
+default-lease-time 7200;
+max-lease-time 86400;
+log-facility local7;
+one-lease-per-client true;
+deny duplicates;
+ping-check true;
+update-conflict-detection false;
+
+EOD;
+
+ if (!isset($dhcpv6ifconf['disableauthoritative'])) {
+ $dhcpdv6conf .= "authoritative;\n";
+ }
+
+ if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
+ $dhcpdv6conf .= "always-broadcast on\n";
+ }
+
+ $dhcpdv6ifs = array();
+
+ $dhcpv6num = 0;
+ $nsupdate = false;
+
+ foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
+
+ $ddns_zones = array();
+
+ $ifcfgv6 = $config['interfaces'][$dhcpv6if];
+
+ if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
+ continue;
+ }
+ $ifcfgipv6 = get_interface_ipv6($dhcpv6if);
+ $ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
+ $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
+
+ if ($is_olsr_enabled == true) {
+ if ($dhcpv6ifconf['netmask']) {
+ $subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
+ }
+ }
+
+ $dnscfgv6 = "";
+
+ if ($dhcpv6ifconf['domain']) {
+ $dnscfgv6 .= " option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
+ }
+
+ if ($dhcpv6ifconf['domainsearchlist'] <> "") {
+ $dnscfgv6 .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
+ }
+
+ if (isset($dhcpv6ifconf['ddnsupdate'])) {
+ if ($dhcpv6ifconf['ddnsdomain'] <> "") {
+ $dnscfgv6 .= " ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
+ }
+ $dnscfgv6 .= " ddns-update-style interim;\n";
+ $nsupdate = true;
+ }
+
+ if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
+ $dnscfgv6 .= " option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
+ } else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
+ $dnscfgv6 .= " option dhcp6.name-servers {$ifcfgipv6};";
+ } else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
+ $dns_arrv6 = array();
+ foreach ($syscfg['dnsserver'] as $dnsserver) {
+ if (is_ipaddrv6($dnsserver)) {
+ $dns_arrv6[] = $dnsserver;
+ }
+ }
+ if (!empty($dns_arrv6)) {
+ $dnscfgv6 .= " option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
+ }
+ }
+
+ if ($dhcpv6ifconf['domain']) {
+ $newzone = array();
+ $newzone['domain-name'] = $dhcpv6ifconf['domain'];
+ $newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
+ $ddns_zones[] = $newzone;
+ }
+
+ if (is_ipaddrv6($ifcfgipv6)) {
+ $dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
+ } else {
+ $subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
+ $dhcpdv6conf .= "subnet6 {$subnet6}/64";
+ }
+ $dhcpdv6conf .= " {\n";
+
+ $dhcpdv6conf .= <<<EOD
+ range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
+$dnscfgv6
+
+EOD;
+
+ if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
+ $dhcpdv6conf .= " prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
+ }
+ if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
+ $dhcpdv6conf .= " option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
+ }
+ // default-lease-time
+ if ($dhcpv6ifconf['defaultleasetime']) {
+ $dhcpdv6conf .= " default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
+ }
+
+ // max-lease-time
+ if ($dhcpv6ifconf['maxleasetime']) {
+ $dhcpdv6conf .= " max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
+ }
+
+ // ntp-servers
+ if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
+ $ntpservers = array();
+ foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
+ if (is_ipaddrv6($ntpserver)) {
+ $ntpservers[] = $ntpserver;
+ }
+ }
+ if (count($ntpservers) > 0) {
+ $dhcpdv6conf .= " option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
+ }
+ }
+ // tftp-server-name
+ /* Needs ISC DHCPD support
+ if ($dhcpv6ifconf['tftp'] <> "") {
+ $dhcpdv6conf .= " option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
+ }
+ */
+
+ // Handle option, number rowhelper values
+ $dhcpdv6conf .= "\n";
+ if ($dhcpv6ifconf['numberoptions']['item']) {
+ foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
+ $dhcpdv6conf .= " option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
+ }
+ }
+
+ // ldap-server
+ if ($dhcpv6ifconf['ldap'] <> "") {
+ $dhcpdv6conf .= " option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
+ }
+
+ // net boot information
+ if (isset($dhcpv6ifconf['netboot'])) {
+ if (!empty($dhcpv6ifconf['bootfile_url'])) {
+ $dhcpdv6conf .= " option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
+ }
+ }
+
+ $dhcpdv6conf .= "}\n";
+
+ /* add static mappings */
+ /* Needs to use DUID */
+ if (is_array($dhcpv6ifconf['staticmap'])) {
+ $i = 0;
+ foreach ($dhcpv6ifconf['staticmap'] as $sm) {
+ $dhcpdv6conf .= <<<EOD
+host s_{$dhcpv6if}_{$i} {
+ host-identifier option dhcp6.client-id {$sm['duid']};
+
+EOD;
+ if ($sm['ipaddrv6']) {
+ $dhcpdv6conf .= " fixed-address6 {$sm['ipaddrv6']};\n";
+ }
+
+ if ($sm['hostname']) {
+ $dhhostname = str_replace(" ", "_", $sm['hostname']);
+ $dhhostname = str_replace(".", "_", $dhhostname);
+ $dhcpdv6conf .= " option host-name {$dhhostname};\n";
+ }
+ if ($sm['filename']) {
+ $dhcpdv6conf .= " filename \"{$sm['filename']}\";\n";
+ }
+
+ if ($sm['rootpath']) {
+ $dhcpdv6conf .= " option root-path \"{$sm['rootpath']}\";\n";
+ }
+
+ $dhcpdv6conf .= "}\n";
+ $i++;
+ }
+ }
+
+ if ($dhcpv6ifconf['domain']) {
+ $dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
+ $dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
+ }
+
+ if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
+ if (preg_match("/poes/si", $dhcpv6if)) {
+ /* magic here */
+ $dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
+ } else {
+ $realif = get_real_interface($dhcpv6if, "inet6");
+ if (stristr("$realif", "bridge")) {
+ $mac = get_interface_mac($realif);
+ $v6address = generate_ipv6_from_mac($mac);
+ /* Create link local address for bridges */
+ mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
+ }
+ $realif = escapeshellcmd($realif);
+ $dhcpdv6ifs[] = $realif;
+ }
+ }
+ }
+
+ if ($nsupdate) {
+ $dhcpdv6conf .= "ddns-update-style interim;\n";
+ } else {
+ $dhcpdv6conf .= "ddns-update-style none;\n";
+ }
+
+ /* write dhcpdv6.conf */
+ if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
+ log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
+ if (platform_booting()) {
+ printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
+ }
+ unset($dhcpdv6conf);
+ return 1;
+ }
+ unset($dhcpdv6conf);
+
+ /* create an empty leases v6 database */
+ if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
+ @touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
+ }
+
+ /* make sure there isn't a stale dhcpdv6.pid file, which may make dhcpdv6 fail to start. */
+ /* if we get here, dhcpdv6 has been killed and is not started yet */
+ unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
+
+ /* fire up dhcpd in a chroot */
+ if (count($dhcpdv6ifs) > 0) {
+ mwexec("/usr/local/sbin/dhcpd -6 -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpdv6.conf -pf {$g['varrun_path']}/dhcpdv6.pid " .
+ join(" ", $dhcpdv6ifs));
+ mwexec("/usr/local/sbin/dhcpleases6 -c \"/usr/local/bin/php-cgi -f /usr/local/sbin/prefixes.php|/bin/sh\" -l {$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
+ }
+ if (platform_booting()) {
+ print gettext("done.") . "\n";
+ }
+
+ return 0;
+}
+
+function services_igmpproxy_configure() {
+ global $config, $g;
+
+ /* kill any running igmpproxy */
+ killbyname("igmpproxy");
+
+ if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
+ return 1;
+ }
+
+ $iflist = get_configured_interface_list();
+
+ $igmpconf = <<<EOD
+
+##------------------------------------------------------
+## Enable Quickleave mode (Sends Leave instantly)
+##------------------------------------------------------
+quickleave
+
+EOD;
+
+ foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
+ unset($iflist[$igmpcf['ifname']]);
+ $realif = get_real_interface($igmpcf['ifname']);
+ if (empty($igmpcf['threshold'])) {
+ $threshld = 1;
+ } else {
+ $threshld = $igmpcf['threshold'];
+ }
+ $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
+
+ if ($igmpcf['address'] <> "") {
+ $item = explode(" ", $igmpcf['address']);
+ foreach ($item as $iww) {
+ $igmpconf .= "altnet {$iww}\n";
+ }
+ }
+ $igmpconf .= "\n";
+ }
+ foreach ($iflist as $ifn) {
+ $realif = get_real_interface($ifn);
+ $igmpconf .= "phyint {$realif} disabled\n";
+ }
+ $igmpconf .= "\n";
+
+ $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
+ if (!$igmpfl) {
+ log_error(gettext("Could not write Igmpproxy configuration file!"));
+ return;
+ }
+ fwrite($igmpfl, $igmpconf);
+ fclose($igmpfl);
+ unset($igmpconf);
+
+ /* NOTE: -d4 means everything LOG_WARNING and smaller */
+ mwexec("/usr/local/sbin/igmpproxy -d4 -c {$g['tmp_path']}/igmpproxy.conf");
+ log_error(gettext("Started IGMP proxy service."));
+
+ return 0;
+}
+
+function services_dhcrelay_configure() {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dhcrelay_configure() being called $mt\n";
+ }
+
+ /* kill any running dhcrelay */
+ killbypid("{$g['varrun_path']}/dhcrelay.pid");
+
+ $dhcrelaycfg =& $config['dhcrelay'];
+
+ /* DHCPRelay enabled on any interfaces? */
+ if (!isset($dhcrelaycfg['enable'])) {
+ return 0;
+ }
+
+ if (platform_booting()) {
+ echo gettext("Starting DHCP relay service...");
+ } else {
+ sleep(1);
+ }
+
+ $iflist = get_configured_interface_list();
+
+ $dhcifaces = explode(",", $dhcrelaycfg['interface']);
+ foreach ($dhcifaces as $dhcrelayif) {
+ if (!isset($iflist[$dhcrelayif]) ||
+ link_interface_to_bridge($dhcrelayif)) {
+ continue;
+ }
+
+ if (is_ipaddr(get_interface_ip($dhcrelayif))) {
+ $dhcrelayifs[] = get_real_interface($dhcrelayif);
+ }
+ }
+
+ $srvips = explode(",", $dhcrelaycfg['server']);
+ if (!is_array($srvips)) {
+ log_error("No destination IP has been configured!");
+ return;
+ }
+
+ $dhcrelayifs = array_unique($dhcrelayifs);
+
+ /* fire up dhcrelay */
+ if (empty($dhcrelayifs)) {
+ log_error("No suitable interface found for running dhcrelay!");
+ return; /* XXX */
+ }
+
+ $cmd = "/usr/local/sbin/dhcrelay -i " . implode(" -i ", $dhcrelayifs);
+
+ if (isset($dhcrelaycfg['agentoption'])) {
+ $cmd .= " -a -m replace";
+ }
+
+ $cmd .= " " . implode(" ", $srvips);
+ mwexec($cmd);
+ unset($cmd);
+
+ return 0;
+}
+
+function services_dhcrelay6_configure() {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dhcrelay6_configure() being called $mt\n";
+ }
+
+ /* kill any running dhcrelay */
+ killbypid("{$g['varrun_path']}/dhcrelay6.pid");
+
+ $dhcrelaycfg =& $config['dhcrelay6'];
+
+ /* DHCPv6 Relay enabled on any interfaces? */
+ if (!isset($dhcrelaycfg['enable'])) {
+ return 0;
+ }
+
+ if (platform_booting()) {
+ echo gettext("Starting DHCPv6 relay service...");
+ } else {
+ sleep(1);
+ }
+
+ $iflist = get_configured_interface_list();
+
+ $dhcifaces = explode(",", $dhcrelaycfg['interface']);
+ foreach ($dhcifaces as $dhcrelayif) {
+ if (!isset($iflist[$dhcrelayif]) ||
+ link_interface_to_bridge($dhcrelayif)) {
+ continue;
+ }
+
+ if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
+ $dhcrelayifs[] = get_real_interface($dhcrelayif);
+ }
+ }
+ $dhcrelayifs = array_unique($dhcrelayifs);
+
+ $srvips = explode(",", $dhcrelaycfg['server']);
+ if (!is_array($srvips)) {
+ log_error("No destination IP has been configured!");
+ return;
+ }
+
+ /* fire up dhcrelay */
+ if (empty($dhcrelayifs) || empty($srvifaces)) {
+ log_error("No suitable interface found for running dhcrelay -6!");
+ return; /* XXX */
+ }
+
+ $cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
+ foreach ($dhcrelayifs as $dhcrelayif) {
+ $cmd .= " -l {$dhcrelayif}";
+ }
+ foreach ($srvifaces as $srviface) {
+ $cmd .= " -u \"{$srviface}\"";
+ }
+ mwexec($cmd);
+ unset($cmd);
+
+ return 0;
+}
+
+function services_dyndns_configure_client($conf) {
+
+ if (!isset($conf['enable'])) {
+ return;
+ }
+
+ /* load up the dyndns.class */
+ require_once("dyndns.class");
+
+ $dns = new updatedns($dnsService = $conf['type'],
+ $dnsHost = $conf['host'],
+ $dnsUser = $conf['username'],
+ $dnsPass = $conf['password'],
+ $dnsWildcard = $conf['wildcard'],
+ $dnsMX = $conf['mx'],
+ $dnsIf = "{$conf['interface']}",
+ $dnsBackMX = NULL,
+ $dnsServer = NULL,
+ $dnsPort = NULL,
+ $dnsUpdateURL = "{$conf['updateurl']}",
+ $forceUpdate = $conf['force'],
+ $dnsZoneID = $conf['zoneid'],
+ $dnsTTL = $conf['ttl'],
+ $dnsResultMatch = "{$conf['resultmatch']}",
+ $dnsRequestIf = "{$conf['requestif']}",
+ $dnsID = "{$conf['id']}",
+ $dnsVerboseLog = $conf['verboselog'],
+ $curlIpresolveV4 = $conf['curl_ipresolve_v4'],
+ $curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
+}
+
+function services_dyndns_configure($int = "") {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dyndns_configure() being called $mt\n";
+ }
+
+ $dyndnscfg = $config['dyndnses']['dyndns'];
+ $gwgroups = return_gateway_groups_array();
+ if (is_array($dyndnscfg)) {
+ if (platform_booting()) {
+ echo gettext("Starting DynDNS clients...");
+ }
+
+ foreach ($dyndnscfg as $dyndns) {
+ if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
+ $dyndns['verboselog'] = isset($dyndns['verboselog']);
+ $dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
+ $dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
+ services_dyndns_configure_client($dyndns);
+ sleep(1);
+ }
+ }
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ return 0;
+}
+
+function dyndnsCheckIP($int) {
+ global $config;
+ $ip_address = get_interface_ip($int);
+ if (is_private_ip($ip_address)) {
+ $gateways_status = return_gateways_status(true);
+ // If the gateway for this interface is down, then the external check cannot work.
+ // Avoid the long wait for the external check to timeout.
+ if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
+ return "down";
+ }
+ $hosttocheck = "http://checkip.dyndns.org";
+ $ip_ch = curl_init($hosttocheck);
+ curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
+ curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
+ curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
+ curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ $ip_result_page = curl_exec($ip_ch);
+ curl_close($ip_ch);
+ $ip_result_decoded = urldecode($ip_result_page);
+ preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
+ $ip_address = trim($matches[1]);
+ }
+ return $ip_address;
+}
+
+function services_dnsmasq_configure() {
+ global $config, $g;
+ $return = 0;
+
+ // hard coded args: will be removed to avoid duplication if specified in custom_options
+ $standard_args = array(
+ "dns-forward-max" => "--dns-forward-max=5000",
+ "cache-size" => "--cache-size=10000",
+ "local-ttl" => "--local-ttl=1"
+ );
+
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dnsmasq_configure() being called $mt\n";
+ }
+
+ /* kill any running dnsmasq */
+ if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
+ sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
+ }
+
+ if (isset($config['dnsmasq']['enable'])) {
+
+ if (platform_booting()) {
+ echo gettext("Starting DNS forwarder...");
+ } else {
+ sleep(1);
+ }
+
+ /* generate hosts file */
+ if (system_hosts_generate() != 0) {
+ $return = 1;
+ }
+
+ $args = "";
+
+ if (isset($config['dnsmasq']['regdhcp'])) {
+ $args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
+ }
+
+ /* Setup listen port, if non-default */
+ if (is_port($config['dnsmasq']['port'])) {
+ $args .= " --port={$config['dnsmasq']['port']} ";
+ }
+
+ $listen_addresses = "";
+ if (isset($config['dnsmasq']['interface'])) {
+ $interfaces = explode(",", $config['dnsmasq']['interface']);
+ foreach ($interfaces as $interface) {
+ if (is_ipaddrv4($interface)) {
+ $listen_addresses .= " --listen-address={$interface} ";
+ } else if (is_ipaddrv6($interface)) {
+ /*
+ * XXX: Since dnsmasq does not support link-local address
+ * with scope specified. These checks are being done.
+ */
+ if (is_linklocal($interface) && strstr($interface, "%")) {
+ $tmpaddrll6 = explode("%", $interface);
+ $listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
+ } else {
+ $listen_addresses .= " --listen-address={$interface} ";
+ }
+ } else if (strstr($interface, "_vip")) {
+ $laddr = get_configured_carp_interface_list($interface);
+ if (is_ipaddr($laddr)) {
+ $listen_addresses .= " --listen-address={$laddr} ";
+ }
+ } else {
+ $if = get_real_interface($interface);
+ if (does_interface_exist($if)) {
+ $laddr = get_interface_ip($interface);
+ if (is_ipaddrv4($laddr)) {
+ $listen_addresses .= " --listen-address={$laddr} ";
+ }
+ $laddr6 = get_interface_ipv6($interface);
+ if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
+ /*
+ * XXX: Since dnsmasq does not support link-local address
+ * with scope specified. These checks are being done.
+ */
+ if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
+ $tmpaddrll6 = explode("%", $laddr6);
+ $listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
+ } else {
+ $listen_addresses .= " --listen-address={$laddr6} ";
+ }
+ }
+ }
+ }
+ }
+ if (!empty($listen_addresses)) {
+ $args .= " {$listen_addresses} ";
+ if (isset($config['dnsmasq']['strictbind'])) {
+ $args .= " --bind-interfaces ";
+ }
+ }
+ }
+
+ /* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
+ /* Only make entries for reverse domains that do not have a matching domain override. */
+ if (isset($config['dnsmasq']['no_private_reverse'])) {
+ /* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
+ /* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
+ /* Just the pfSense WAN might get a CGN address from an ISP. */
+
+ // Build an array of domain overrides to help in checking for matches.
+ $override_a = array();
+ if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
+ foreach ($config['dnsmasq']['domainoverrides'] as $override) {
+ $override_a[$override['domain']] = "y";
+ }
+ }
+
+ // Build an array of the private reverse lookup domain names
+ $reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
+ // Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
+ for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
+ $reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
+ }
+
+ // Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
+ foreach ($reverse_domain_a as $reverse_domain) {
+ if (!isset($override_a[$reverse_domain])) {
+ $args .= " --server=/$reverse_domain/ ";
+ }
+ }
+ unset($override_a);
+ unset($reverse_domain_a);
+ }
+
+ /* Setup forwarded domains */
+ if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
+ foreach ($config['dnsmasq']['domainoverrides'] as $override) {
+ if ($override['ip'] == "!") {
+ $override[ip] = "";
+ }
+ $args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
+ }
+ }
+
+ /* Allow DNS Rebind for forwarded domains */
+ if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
+ if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
+ foreach ($config['dnsmasq']['domainoverrides'] as $override) {
+ $args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
+ }
+ }
+ }
+
+ if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
+ $dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
+ }
+
+ if (isset($config['dnsmasq']['strict_order'])) {
+ $args .= " --strict-order ";
+ }
+
+ if (isset($config['dnsmasq']['domain_needed'])) {
+ $args .= " --domain-needed ";
+ }
+
+ if ($config['dnsmasq']['custom_options']) {
+ foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
+ $args .= " " . escapeshellarg("--{$c}");
+ $p = explode('=', $c);
+ if (array_key_exists($p[0], $standard_args)) {
+ unset($standard_args[$p[0]]);
+ }
+ }
+ }
+ $args .= ' ' . implode(' ', array_values($standard_args));
+
+ /* run dnsmasq */
+ $cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
+ //log_error("dnsmasq command: {$cmd}");
+ mwexec_bg($cmd);
+ unset($args);
+
+ system_dhcpleases_configure();
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ if (!platform_booting()) {
+ if (services_dhcpd_configure() != 0) {
+ $return = 1;
+ }
+ }
+
+ return $return;
+}
+
+function services_unbound_configure() {
+ global $config, $g;
+ $return = 0;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_unbound_configure() being called $mt\n";
+ }
+
+ // kill any running Unbound instance
+ if (file_exists("{$g['varrun_path']}/unbound.pid")) {
+ sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
+ }
+
+ if (isset($config['unbound']['enable'])) {
+ if (platform_booting()) {
+ echo gettext("Starting DNS Resolver...");
+ } else {
+ sleep(1);
+ }
+
+ /* generate hosts file */
+ if (system_hosts_generate() != 0) {
+ $return = 1;
+ }
+
+ require_once('/etc/inc/unbound.inc');
+ sync_unbound_service();
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+
+ system_dhcpleases_configure();
+ }
+
+ if (!platform_booting()) {
+ if (services_dhcpd_configure() != 0) {
+ $return = 1;
+ }
+ }
+
+ return $return;
+}
+
+function services_snmpd_configure() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_snmpd_configure() being called $mt\n";
+ }
+
+ /* kill any running snmpd */
+ sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
+ sleep(2);
+ if (is_process_running("bsnmpd")) {
+ mwexec("/usr/bin/killall bsnmpd", true);
+ }
+
+ if (isset($config['snmpd']['enable'])) {
+
+ if (platform_booting()) {
+ echo gettext("Starting SNMP daemon... ");
+ }
+
+ /* generate snmpd.conf */
+ $fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
+ return 1;
+ }
+
+
+ $snmpdconf = <<<EOD
+location := "{$config['snmpd']['syslocation']}"
+contact := "{$config['snmpd']['syscontact']}"
+read := "{$config['snmpd']['rocommunity']}"
+
+EOD;
+
+/* No docs on what write strings do there for disable for now.
+ if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
+ $snmpdconf .= <<<EOD
+# write string
+write := "{$config['snmpd']['rwcommunity']}"
+
+EOD;
+ }
+*/
+
+
+ if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
+ $snmpdconf .= <<<EOD
+# SNMP Trap support.
+traphost := {$config['snmpd']['trapserver']}
+trapport := {$config['snmpd']['trapserverport']}
+trap := "{$config['snmpd']['trapstring']}"
+
+
+EOD;
+ }
+
+ $platform = trim(file_get_contents('/etc/platform'));
+ if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
+ $platform = $g['product_name'];
+ }
+ $sysDescr = "{$g['product_name']} " . php_uname("n") .
+ " {$g['product_version']} {$platform} " . php_uname("s") .
+ " " . php_uname("r") . " " . php_uname("m");
+
+ $snmpdconf .= <<<EOD
+system := 1 # pfSense
+%snmpd
+sysDescr = "{$sysDescr}"
+begemotSnmpdDebugDumpPdus = 2
+begemotSnmpdDebugSyslogPri = 7
+begemotSnmpdCommunityString.0.1 = $(read)
+
+EOD;
+
+/* No docs on what write strings do there for disable for now.
+ if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdCommunityString.0.2 = $(write)
+
+EOD;
+ }
+*/
+
+
+ if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
+ $snmpdconf .= <<<EOD
+begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
+begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
+begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
+
+EOD;
+ }
+
+
+ $snmpdconf .= <<<EOD
+begemotSnmpdCommunityDisable = 1
+
+EOD;
+
+ if (isset($config['snmpd']['bindlan'])) {
+ $config['snmpd']['bindip'] = 'lan';
+ unset($config['snmpd']['bindlan']);
+ }
+ $bind_to_ip = "0.0.0.0";
+ if (isset($config['snmpd']['bindip'])) {
+ if (is_ipaddr($config['snmpd']['bindip'])) {
+ $bind_to_ip = $config['snmpd']['bindip'];
+ } else {
+ $if = get_real_interface($config['snmpd']['bindip']);
+ if (does_interface_exist($if)) {
+ $bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
+ }
+ }
+ }
+
+ if (is_port($config['snmpd']['pollport'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
+
+EOD;
+
+ }
+
+ $snmpdconf .= <<<EOD
+begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
+begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
+
+# These are bsnmp macros not php vars.
+sysContact = $(contact)
+sysLocation = $(location)
+sysObjectId = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
+
+snmpEnableAuthenTraps = 2
+
+EOD;
+
+ if (is_array($config['snmpd']['modules'])) {
+ if (isset($config['snmpd']['modules']['mibii'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."mibII" = "/usr/lib/snmp_mibII.so"
+
+EOD;
+ }
+
+ if (isset($config['snmpd']['modules']['netgraph'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
+%netgraph
+begemotNgControlNodeName = "snmpd"
+
+EOD;
+ }
+
+ if (isset($config['snmpd']['modules']['pf'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."pf" = "/usr/lib/snmp_pf.so"
+
+EOD;
+ }
+
+ if (isset($config['snmpd']['modules']['hostres'])) {
+ /* XXX: hostres module crashes APU - ticket #4403 */
+ $specplatform = system_identify_specific_platform();
+ if ($specplatform['name'] == 'APU') {
+ log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
+ } else {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."hostres" = "/usr/lib/snmp_hostres.so"
+
+EOD;
+ }
+ unset($specplatform);
+ }
+
+ if (isset($config['snmpd']['modules']['bridge'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so"
+# config must end with blank line
+
+EOD;
+ }
+ if (isset($config['snmpd']['modules']['ucd'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."ucd" = "/usr/local/lib/snmp_ucd.so"
+
+EOD;
+ }
+ if (isset($config['snmpd']['modules']['regex'])) {
+ $snmpdconf .= <<<EOD
+begemotSnmpdModulePath."regex" = "/usr/local/lib/snmp_regex.so"
+
+EOD;
+ }
+ }
+
+ fwrite($fd, $snmpdconf);
+ fclose($fd);
+ unset($snmpdconf);
+
+ if (isset($config['snmpd']['bindlan'])) {
+ $bindlan = "";
+ }
+
+ /* run bsnmpd */
+ mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
+ "{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ }
+
+ return 0;
+}
+
+function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "services_dnsupdate_process() being called $mt\n";
+ }
+
+ /* Dynamic DNS updating active? */
+ if (is_array($config['dnsupdates']['dnsupdate'])) {
+ $notify_text = "";
+ foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
+ if (!isset($dnsupdate['enable'])) {
+ continue;
+ }
+ if (!empty($int) && $int != $dnsupdate['interface']) {
+ continue;
+ }
+ if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
+ continue;
+ }
+
+ /* determine interface name */
+ $if = get_real_interface($dnsupdate['interface']);
+
+ if (isset($dnsupdate['usepublicip'])) {
+ $wanip = dyndnsCheckIP($dnsupdate['interface']);
+ } else {
+ $wanip = get_interface_ip($dnsupdate['interface']);
+ }
+
+ $wanipv6 = get_interface_ipv6($dnsupdate['interface']);
+ $cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
+ $currentTime = time();
+
+ if ($wanip || $wanipv6) {
+ $keyname = $dnsupdate['keyname'];
+ /* trailing dot */
+ if (substr($keyname, -1) != ".") {
+ $keyname .= ".";
+ }
+
+ $hostname = $dnsupdate['host'];
+ /* trailing dot */
+ if (substr($hostname, -1) != ".") {
+ $hostname .= ".";
+ }
+
+ /* write private key file
+ this is dumb - public and private keys are the same for HMAC-MD5,
+ but nsupdate insists on having both */
+ $fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
+ $privkey = <<<EOD
+Private-key-format: v1.2
+Algorithm: 157 (HMAC)
+Key: {$dnsupdate['keydata']}
+
+EOD;
+ fwrite($fd, $privkey);
+ fclose($fd);
+
+ /* write public key file */
+ if ($dnsupdate['keytype'] == "zone") {
+ $flags = 257;
+ $proto = 3;
+ } else if ($dnsupdate['keytype'] == "host") {
+ $flags = 513;
+ $proto = 3;
+ } else if ($dnsupdate['keytype'] == "user") {
+ $flags = 0;
+ $proto = 2;
+ }
+
+ $fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.key", "w");
+ fwrite($fd, "{$keyname} IN KEY {$flags} {$proto} 157 {$dnsupdate['keydata']}\n");
+ fclose($fd);
+
+ /* generate update instructions */
+ $upinst = "";
+ if (!empty($dnsupdate['server'])) {
+ $upinst .= "server {$dnsupdate['server']}\n";
+ }
+
+ if (file_exists($cacheFile)) {
+ list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
+ }
+ if (file_exists("{$cacheFile}.ipv6")) {
+ list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
+ }
+
+ // 25 Days
+ $maxCacheAgeSecs = 25 * 24 * 60 * 60;
+ $need_update = false;
+
+ conf_mount_rw();
+ /* Update IPv4 if we have it. */
+ if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
+ if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
+ $upinst .= "update delete {$dnsupdate['host']}. A\n";
+ $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
+ $notify_text .= sprintf(gettext("DynDNS updated IP Address (A) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n";
+ @file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
+ log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
+ $need_update = true;
+ } else {
+ log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
+ }
+ } else {
+ @unlink($cacheFile);
+ }
+
+ /* Update IPv6 if we have it. */
+ if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
+ if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
+ $upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
+ $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
+ $notify_text .= sprintf(gettext("DynDNS updated IPv6 Address (AAAA) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n";
+ @file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
+ log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
+ $need_update = true;
+ } else {
+ log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
+ }
+ } else {
+ @unlink("{$cacheFile}.ipv6");
+ }
+ conf_mount_ro();
+
+ $upinst .= "\n"; /* mind that trailing newline! */
+
+ if ($need_update) {
+ @file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
+ unset($upinst);
+ /* invoke nsupdate */
+ $cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
+ if (isset($dnsupdate['usetcp'])) {
+ $cmd .= " -v";
+ }
+ $cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
+ mwexec_bg($cmd);
+ unset($cmd);
+ }
+ }
+ }
+ if (!empty($notify_text)) {
+ notify_all_remote($notify_text);
+ }
+ }
+
+ return 0;
+}
+
+/* configure cron service */
+function configure_cron() {
+ global $g, $config;
+
+ conf_mount_rw();
+ /* preserve existing crontab entries */
+ $crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+
+ for ($i = 0; $i < count($crontab_contents); $i++) {
+ $cron_item =& $crontab_contents[$i];
+ if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
+ array_splice($crontab_contents, $i - 1);
+ break;
+ }
+ }
+ $crontab_contents = implode("\n", $crontab_contents) . "\n";
+
+
+ if (is_array($config['cron']['item'])) {
+ $crontab_contents .= "#\n";
+ $crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
+ $crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
+ $crontab_contents .= "#\n";
+
+ if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
+ $http_proxy = $config['system']['proxyurl'];
+ if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
+ $http_proxy .= ':' . $config['system']['proxyport'];
+ }
+ $crontab_contents .= "HTTP_PROXY={$http_proxy}";
+ }
+
+ foreach ($config['cron']['item'] as $item) {
+ $crontab_contents .= "\n{$item['minute']}\t";
+ $crontab_contents .= "{$item['hour']}\t";
+ $crontab_contents .= "{$item['mday']}\t";
+ $crontab_contents .= "{$item['month']}\t";
+ $crontab_contents .= "{$item['wday']}\t";
+ $crontab_contents .= "{$item['who']}\t";
+ $crontab_contents .= "{$item['command']}";
+ }
+
+ $crontab_contents .= "\n#\n";
+ $crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
+ $crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
+ $crontab_contents .= "#\n\n";
+ }
+
+ /* please maintain the newline at the end of file */
+ file_put_contents("/etc/crontab", $crontab_contents);
+ unset($crontab_contents);
+
+ /* do a HUP kill to force sync changes */
+ sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
+
+ conf_mount_ro();
+}
+
+function upnp_action ($action) {
+ global $g, $config;
+ switch ($action) {
+ case "start":
+ if (file_exists('/var/etc/miniupnpd.conf')) {
+ @unlink("{$g['varrun_path']}/miniupnpd.pid");
+ mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
+ }
+ break;
+ case "stop":
+ killbypid("{$g['varrun_path']}/miniupnpd.pid");
+ while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
+ mwexec('killall miniupnpd 2>/dev/null', true);
+ }
+ mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
+ mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
+ break;
+ case "restart":
+ upnp_action('stop');
+ upnp_action('start');
+ break;
+ }
+}
+
+function upnp_start() {
+ global $config;
+
+ if (!isset($config['installedpackages']['miniupnpd']['config'])) {
+ return;
+ }
+
+ if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
+ echo gettext("Starting UPnP service... ");
+ require_once('/usr/local/pkg/miniupnpd.inc');
+ sync_package_miniupnpd();
+ echo "done.\n";
+ }
+}
+
+function install_cron_job($command, $active = false, $minute = "0", $hour = "*", $monthday = "*", $month = "*", $weekday = "*", $who = "root") {
+ global $config, $g;
+
+ $is_installed = false;
+ $cron_changed = true;
+
+ if (!is_array($config['cron'])) {
+ $config['cron'] = array();
+ }
+ if (!is_array($config['cron']['item'])) {
+ $config['cron']['item'] = array();
+ }
+
+ $x = 0;
+ foreach ($config['cron']['item'] as $item) {
+ if (strstr($item['command'], $command)) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+
+ if ($active) {
+ $cron_item = array();
+ $cron_item['minute'] = $minute;
+ $cron_item['hour'] = $hour;
+ $cron_item['mday'] = $monthday;
+ $cron_item['month'] = $month;
+ $cron_item['wday'] = $weekday;
+ $cron_item['who'] = $who;
+ $cron_item['command'] = $command;
+ if (!$is_installed) {
+ $config['cron']['item'][] = $cron_item;
+ write_config(sprintf(gettext("Installed cron job for %s"), $command));
+ } else {
+ if ($config['cron']['item'][$x] == $cron_item) {
+ $cron_changed = false;
+ log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
+ } else {
+ $config['cron']['item'][$x] = $cron_item;
+ write_config(sprintf(gettext("Updated cron job for %s"), $command));
+ }
+ }
+ } else {
+ if ($is_installed == true) {
+ unset($config['cron']['item'][$x]);
+ write_config(sprintf(gettext("Removed cron job for %s"), $command));
+ }
+ }
+
+ if ($cron_changed) {
+ configure_cron();
+ }
+}
+
+?>
diff --git a/src/etc/inc/shaper.inc b/src/etc/inc/shaper.inc
new file mode 100644
index 0000000..29ae7e9
--- /dev/null
+++ b/src/etc/inc/shaper.inc
@@ -0,0 +1,4969 @@
+<?php
+/*
+ shaper.inc
+ Copyright (C) 2008 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /bin/kill /sbin/kldload /bin/rm /bin/ps
+ pfSense_MODULE: shaper
+*/
+
+/* XXX: needs some reducing on include. */
+/* include all configuration functions. */
+require_once("globals.inc");
+require_once("functions.inc");
+require_once("util.inc");
+require_once("notices.inc");
+
+/*
+ * I admit :) this is derived from xmlparse.inc StartElement()
+ */
+function &get_reference_to_me_in_config(&$mypath) {
+ global $config;
+
+ $ptr =& $config['shaper'];
+ foreach ($mypath as $indeks) {
+ $ptr =& $ptr['queue'][$indeks];
+ }
+
+ return $ptr;
+}
+
+function unset_object_by_reference(&$mypath) {
+ global $config;
+
+ $ptr =& $config['shaper'];
+ for ($i = 0; $i < count($mypath) - 1; $i++) {
+ $ptr =& $ptr['queue'][$mypath[$i]];
+ }
+ unset($ptr['queue'][$mypath[$i]]);
+}
+
+function &get_dn_reference_to_me_in_config(&$mypath) {
+ global $config;
+
+ $ptr =& $config['dnshaper'];
+ foreach ($mypath as $indeks) {
+ $ptr =& $ptr['queue'][$indeks];
+ }
+
+ return $ptr;
+}
+
+function unset_dn_object_by_reference(&$mypath) {
+ global $config;
+
+ $ptr =& $config['dnshaper'];
+ for ($i = 0; $i < count($mypath) - 1; $i++) {
+ $ptr =& $ptr['queue'][$mypath[$i]];
+ }
+ unset($ptr['queue'][$mypath[$i]]);
+}
+
+function clean_child_queues($type, $mypath) {
+ $ref = &get_reference_to_me_in_config($mypath);
+
+ switch ($type) {
+ case 'HFSC':
+ if (isset($ref['borrow'])) {
+ unset($ref['borrow']);
+ }
+ if (isset($ref['hogs'])) {
+ unset($ref['hogs']);
+ }
+ if (isset($ref['buckets'])) {
+ unset($ref['buckets']);
+ }
+ break;
+ case 'PRIQ':
+ if (isset($ref['borrow'])) {
+ unset($ref['borrow']);
+ }
+ if (isset($ref['bandwidth'])) {
+ unset($ref['bandwidth']);
+ }
+ if (isset($ref['bandwidthtype'])) {
+ unset($ref['bandwidthtype']);
+ }
+ /* fall through */
+ case 'FAIRQ':
+ if (isset($ref['borrow'])) {
+ unset($ref['borrow']);
+ }
+ /* fall through */
+ case 'CBQ':
+ if (isset($ref['realtime'])) {
+ unset($ref['realtime']);
+ }
+ if (isset($ref['realtime1'])) {
+ unset($ref['realtime1']);
+ }
+ if (isset($ref['realtime2'])) {
+ unset($ref['realtime2']);
+ }
+ if (isset($ref['realtime3'])) {
+ unset($ref['realtime3']);
+ }
+ if (isset($ref['upperlimit'])) {
+ unset($ref['upperlimit']);
+ }
+ if (isset($ref['upperlimit1'])) {
+ unset($ref['upperlimit1']);
+ }
+ if (isset($ref['upperlimit2'])) {
+ unset($ref['upperlimit2']);
+ }
+ if (isset($ref['upperlimit3'])) {
+ unset($ref['upperlimit3']);
+ }
+ if (isset($ref['linkshare'])) {
+ unset($ref['linkshare']);
+ }
+ if (isset($ref['linkshare1'])) {
+ unset($ref['linkshare1']);
+ }
+ if (isset($ref['linkshare2'])) {
+ unset($ref['linkshare2']);
+ }
+ if (isset($ref['linkshare3'])) {
+ unset($ref['linkshare3']);
+ }
+ if (isset($ref['hogs'])) {
+ unset($ref['hogs']);
+ }
+ if (isset($ref['buckets'])) {
+ unset($ref['buckets']);
+ }
+ break;
+ }
+}
+
+function get_bandwidthtype_scale($type) {
+ switch ($type) {
+ case "Gb":
+ $factor = 1024 * 1024 * 1024;
+ break;
+ case "Mb":
+ $factor = 1024 * 1024;
+ break;
+ case "Kb":
+ $factor = 1024;
+ break;
+ case "b":
+ default:
+ $factor = 1;
+ break;
+ }
+ return intval($factor);
+}
+
+function get_hfsc_bandwidth($object, $bw) {
+ $pattern= "/[0-9]+/";
+ if (preg_match($pattern, $bw, $match)) {
+ $bw_1 = $match[1];
+ } else {
+ return 0;
+ }
+ $pattern= "/(b|Kb|Mb|Gb|%)/";
+ if (preg_match($pattern, $bw, $match)) {
+ switch ($match[1]) {
+ case '%':
+ $bw_1 = $bw_1 / 100 * get_interface_bandwidth($object);
+ break;
+ default:
+ $bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
+ break;
+ }
+ return floatval($bw_1);
+ } else {
+ return 0;
+ }
+}
+
+function get_interface_bandwidth($object) {
+ global $altq_list_queues;
+
+ $int = $object->GetInterface();
+ $altq =& $altq_list_queues[$int];
+ if ($altq) {
+ $bw_3 = $altq->GetBandwidth();
+ $bw_3 = $bw_3 * get_bandwidthtype_scale($altq->GetBwscale());
+ return floatval($bw_3);
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * This is duplicated here since we cannot include guiconfig.inc.
+ * Including it makes all stuff break.
+ */
+function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) {
+
+ /* check for bad control characters */
+ foreach ($postdata as $pn => $pd) {
+ if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
+ $input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
+ }
+ }
+
+ for ($i = 0; $i < count($reqdfields); $i++) {
+ if ($postdata[$reqdfields[$i]] == "") {
+ $input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
+ }
+ }
+}
+
+function cleanup_queue_from_rules($queue) {
+ global $config;
+
+ foreach ($config['filter']['rule'] as $rule) {
+ if ($rule['defaultqueue'] == $queue) {
+ unset($rule['defaultqueue']);
+ }
+ if ($rule['ackqueue'] == $queue) {
+ unset($rule['ackqueue']);
+ }
+ }
+}
+
+function cleanup_dnqueue_from_rules($queue) {
+ global $config;
+
+ foreach ($config['filter']['rule'] as $rule) {
+ if ($rule['dnpipe'] == $queue) {
+ unset($rule['dnpipe']);
+ }
+ if ($rule['pdnpipe'] == $queue) {
+ unset($rule['pdnpipe']);
+ }
+ }
+}
+
+class altq_root_queue {
+ var $interface;
+ var $tbrconfig ;
+ var $bandwidth;
+ var $bandwidthtype; /* b, Kb, Mb */
+ var $scheduler;
+ var $qlimit;
+ var $queues = array();
+ var $qenabled = false;
+ var $link;
+ var $available_bw; /* in b/s */
+
+ /* Accessor functions */
+ function GetAvailableBandwidth() {
+ return $this->available_bw;
+ }
+ function SetAvailableBandwidth($bw) {
+ $this->available_bw = $bw;
+ }
+ function GetDefaultQueuePresent() {
+ if (!empty($this->queues)) {
+ foreach ($this->queues as $q) {
+ if ($q->GetDefault()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ function SetLink($link) {
+ $this->link = $link;
+ }
+ function GetLink() {
+ return $this->link;
+ }
+ function GetEnabled() {
+ return $this->qenabled;
+ }
+ function SetEnabled($value) {
+ $this->qenabled = $value;
+ }
+ function CanHaveChildren() {
+ if ($this->GetScheduler() == "CODELQ") {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ function CanBeDeleted() {
+ return false;
+ }
+ function GetQname() {
+ return $this->interface;
+ }
+ function SetQname($name) {
+ $this->interface = trim($name);
+ }
+ function GetInterface() {
+ return $this->interface;
+ }
+ function SetInterface($name) {
+ $this->interface = trim($name);
+ }
+ function GetTbrConfig() {
+ return $this->tbrconfig;
+ }
+ function SetTbrConfig($tbrconfig) {
+ $this->tbrconfig = $tbrconfig;
+ }
+ function GetBandwidth() {
+ return $this->bandwidth;
+ }
+ function SetBandwidth($bw) {
+ $this->bandwidth = $bw;
+ }
+ function GetBwscale() {
+ return $this->bandwidthtype;
+ }
+ function SetBwscale($bwscale) {
+ $this->bandwidthtype = $bwscale;
+ }
+ function GetScheduler() {
+ return $this->scheduler;
+ }
+ function SetScheduler($scheduler) {
+ $this->scheduler = trim($scheduler);
+ }
+ function GetQlimit() {
+ return $this->qlimit;
+ }
+ function SetQlimit($limit) {
+ $this->qlimit = $limit;
+ }
+
+ function validate_input($data, &$input_errors) {
+
+ $reqdfields[] = "bandwidth";
+ $reqdfieldsn[] = gettext("Bandwidth");
+ $reqdfields[] = "bandwidthtype";
+ $reqdfieldsn[] = gettext("Bandwidthtype");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
+ $input_errors[] = gettext("Bandwidth must be an integer.");
+ }
+ if ($data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth cannot be negative.");
+ }
+ if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
+ $input_errors[] = gettext("Qlimit must be an integer.");
+ }
+ if ($data['qlimit'] < 0) {
+ $input_errors[] = gettext("Qlimit must be positive.");
+ }
+ if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) {
+ $input_errors[] = gettext("Tbrsize must be an integer.");
+ }
+ if ($data['tbrconfig'] < 0) {
+ $input_errors[] = gettext("Tbrsize must be positive.");
+ }
+ }
+
+ /* Implement this to shorten some code on the frontend page */
+ function ReadConfig(&$conf) {
+ if (isset($conf['tbrconfig'])) {
+ $this->SetTbrConfig($conf['tbrconfig']);
+ } else {
+ $this->SetTbrConfig($conf['tbrconfig']);
+ }
+ $this->SetBandwidth($conf['bandwidth']);
+ if ($conf['bandwidthtype'] <> "") {
+ $this->SetBwscale($conf['bandwidthtype']);
+ }
+ if (isset($conf['scheduler'])) {
+ if ($this->GetScheduler() != $conf['scheduler']) {
+ foreach ($this->queues as $q) {
+ clean_child_queues($conf['scheduler'], $this->GetLink());
+ $q->clean_queue($conf['scheduler']);
+ }
+ }
+ $this->SetScheduler($conf['scheduler']);
+ }
+ if (isset($conf['qlimit']) && $conf['qlimit'] <> "") {
+ $this->SetQlimit($conf['qlimit']);
+ } else {
+ $this->SetQlimit("");
+ }
+ if (isset($conf['name'])) {
+ $this->SetQname($conf['name']);
+ }
+ if (!empty($conf['enabled'])) {
+ $this->SetEnabled($conf['enabled']);
+ } else {
+ $this->SetEnabled("");
+ }
+ }
+
+ function copy_queue($interface, &$cflink) {
+ $cflink['interface'] = $interface;
+ $cflink['name'] = $interface;
+ $cflink['scheduler'] = $this->GetScheduler();
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['qlimit'] = $this->GetQlimit();
+ $cflink['tbrconfig'] = $this->GetTbrConfig();
+ $cflink['enabled'] = $this->GetEnabled();
+ if (is_array($this->queues)) {
+ $cflink['queue'] = array();
+ foreach ($this->queues as $q) {
+ $cflink['queue'][$q->GetQname()] = array();
+ $q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
+ }
+ }
+ }
+
+ function &get_queue_list(&$q = null) {
+ $qlist = array();
+
+ //$qlist[$this->GetQname()] = & $this;
+ if (is_array($this->queues)) {
+ foreach ($this->queues as $queue) {
+ $queue->get_queue_list($qlist);
+ }
+ }
+ return $qlist;
+ }
+
+ function &add_queue($interface, &$queue, &$path, &$input_errors) {
+
+ if (!is_array($this->queues)) {
+ $this->queues = array();
+ }
+
+ switch ($this->GetScheduler()) {
+ case "PRIQ":
+ $q =& new priq_queue();
+ break;
+ case "HFSC":
+ $q =& new hfsc_queue();
+ break;
+ case "CBQ":
+ $q =& new cbq_queue();
+ break;
+ case "FAIRQ":
+ $q =& new fairq_queue();
+ break;
+ default:
+ /* XXX: but should not happen anyway */
+ return;
+ break;
+ }
+ $q->SetLink($path);
+ $q->SetInterface($this->GetInterface());
+ $q->SetEnabled("on");
+ $q->SetParent($this);
+ $q->ReadConfig($queue);
+ $q->validate_input($queue, $input_errors);
+ if (count($input_errors)) {
+ log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
+ return $q;
+ }
+
+ if (isset($queue['bandwidth'])) {
+ switch ($queue['bandwidthtype']) {
+ case "%":
+ $myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100;
+ break;
+ default:
+ $myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwidthtype']);
+ break;
+ }
+ }
+ $q->SetAvailableBandwidth($myBw);
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
+ $this->queues[$q->GetQname()] = &$q;
+ ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
+ if (is_array($queue['queue'])) {
+ foreach ($queue['queue'] as $key1 => $que) {
+ array_push($path, $key1);
+ $q->add_queue($q->GetInterface(), $que, $path, $input_errors);
+ array_pop($path);
+ }
+ }
+
+ return $q;
+ }
+
+ /* interface here might be optional */
+ function &find_queue($interface, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+ foreach ($this->queues as $q) {
+ $result =& $q->find_queue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function &find_parentqueue($interface, $qname) {
+ if ($qname == $interface) {
+ $result = NULL;
+ } else if ($this->queues[$qname]) {
+ $result = $this;
+ } else if ($this->GetScheduler() <> "PRIQ") {
+ foreach ($this->queues as $q) {
+ $result = $q->find_parentqueue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+ }
+
+ function build_tree() {
+ global $shaperIFlist;
+
+ $tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&amp;queue=". $this->GetInterface()."&amp;action=show";
+ $tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
+ if (is_array($this->queues)) {
+ $tree .= "<ul>";
+ foreach ($this->queues as $q) {
+ $tree .= $q->build_tree();
+ }
+ $tree .= "</ul>";
+ }
+ $tree .= "</li>";
+ return $tree;
+ }
+
+ function delete_queue() {
+ foreach ($this->queues as $q) {
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
+ $q->delete_queue();
+ }
+ unset_object_by_reference($this->GetLink());
+ }
+
+ function delete_all() {
+ if (count($this->queues)) {
+ foreach ($this->queues as $q) {
+ $q->delete_all();
+ unset_object_by_reference($q->GetLink());
+ unset($q);
+ }
+ unset($this->queues);
+ }
+ }
+
+ /*
+ * First it spits:
+ * altq on $interface ..............
+ * then it goes like
+ * foreach ($queues as $qkey => $queue) {
+ * this->queues[$qkey]->build_rule();
+ * }
+ */
+ function build_rules(&$default = false) {
+ if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
+ $default = false;
+ $rules = " altq on " . get_real_interface($this->GetInterface());
+ if ($this->GetScheduler()) {
+ $rules .= " ".strtolower($this->GetScheduler());
+ }
+ if ($this->GetQlimit() > 0) {
+ $rules .= " qlimit " . $this->GetQlimit() . " ";
+ }
+ if ($this->GetBandwidth()) {
+ $rules .= " bandwidth ".trim($this->GetBandwidth());
+ if ($this->GetBwscale()) {
+ $rules .= $this->GetBwscale();
+ }
+ }
+ if ($this->GetTbrConfig()) {
+ $rules .= " tbrsize ".$this->GetTbrConfig();
+ }
+ if (count($this->queues)) {
+ $i = count($this->queues);
+ $rules .= " queue { ";
+ foreach ($this->queues as $qkey => $qnone) {
+ if ($i > 1) {
+ $i--;
+ $rules .= " {$qkey}, ";
+ } else {
+ $rules .= " {$qkey} ";
+ }
+ }
+ $rules .= " } \n";
+ foreach ($this->queues as $q) {
+ $rules .= $q->build_rules($default);
+ }
+ }
+
+ if ($default == false) {
+ $error = "SHAPER: no default queue specified for interface ". $this->GetInterface() . ". The interface queue will be enforced as default.";
+ file_notice("Shaper", $error, "Error occurred", "");
+ unset($error);
+ return "\n";
+ }
+ $frule .= $rules;
+ } else if ($this->GetEnabled() == "on" && $this->GetScheduler() == "CODELQ") {
+ $rules = " altq on " . get_real_interface($this->GetInterface());
+ if ($this->GetScheduler()) {
+ $rules .= " ".strtolower($this->GetScheduler());
+ }
+ if ($this->GetQlimit() > 0) {
+ $rules .= " ( qlimit " . $this->GetQlimit() . " ) ";
+ }
+ if ($this->GetBandwidth()) {
+ $rules .= " bandwidth ".trim($this->GetBandwidth());
+ if ($this->GetBwscale()) {
+ $rules .= $this->GetBwscale();
+ }
+ }
+ if ($this->GetTbrConfig()) {
+ $rules .= " tbrsize ".$this->GetTbrConfig();
+ }
+
+ $rules .= " queue";
+ }
+
+ $rules .= " \n";
+ return $rules;
+ }
+
+ function build_javascript() {
+ $javascript = "<script type=\"text/javascript\">";
+ $javascript .= "//<![CDATA[\n";
+ $javascript .= "function mySuspend() {";
+ $javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
+ $javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
+ $javascript .= "else if (document.all)";
+ $javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
+ $javascript .= "}";
+
+ $javascript .= "function myResume() {";
+ $javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
+ $javascript .= "document.layers['shaperarea'].visibility = 'visible';";
+ $javascript .= "else if (document.all) ";
+ $javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
+ $javascript .= "}";
+ $javascript .= "//]]>";
+ $javascript .= "</script>";
+
+ return $javascript;
+ }
+
+ function build_shortform() {
+ global $g;
+
+ $altq =& $this;
+ if ($altq) {
+ $scheduler = ": " . $altq->GetScheduler();
+ }
+ $form = "<tr><td width=\"20%\" class=\"vtable\">";
+ $form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=". $this->GetInterface()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .": ".$scheduler."</a>";
+ $form .= "</td></tr>";
+ $form .= "<tr>";
+ $form .= "<td width=\"50%\" class=\"vncellreq\">";
+ $form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
+ $form .= "</td><td width=\"50%\"></td></tr>";
+ $form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
+ $form .= "<a href=\"firewall_shaper_queues.php?interface=";
+ $form .= $this->GetInterface() . "&amp;queue=";
+ $form .= $this->GetQname() . "&amp;action=delete\">";
+ $form .= "<img src=\"";
+ $form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
+ $form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Disable shaper on interface\" alt=\"disable\" />";
+ $form .= "<span>Disable shaper on interface</span></a></td></tr>";
+
+ return $form;
+
+ }
+ /*
+ * For requesting the parameters of the root queues
+ * to the user like the traffic wizard does.
+ */
+ function build_form() {
+ $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
+ $form .= gettext("Enable/Disable");
+ $form .= "<br /></td><td class=\"vncellreq\">";
+ $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
+ if ($this->GetEnabled() == "on") {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /><span class=\"vexpl\"> " . gettext("Enable/disable discipline and its children") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<strong>".$this->GetQname()."</strong>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Scheduler Type ");
+ $form .= "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<select id=\"scheduler\" name=\"scheduler\" class=\"formselect\">";
+ $form .= "<option value=\"HFSC\"";
+ if ($this->GetScheduler() == "HFSC") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">HFSC</option>";
+ $form .= "<option value=\"CBQ\"";
+ if ($this->GetScheduler() == "CBQ") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">CBQ</option>";
+ $form .= "<option value=\"FAIRQ\"";
+ if ($this->GetScheduler() == "FAIRQ") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">FAIRQ</option>";
+ $form .= "<option value=\"CODELQ\"";
+ if ($this->GetScheduler() == "CODELQ") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">CODELQ</option>";
+ $form .= "<option value=\"PRIQ\"";
+ if ($this->GetScheduler() == "PRIQ") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">PRIQ</option>";
+ $form .= "</select>";
+ $form .= "<br /> <span class=\"vexpl\">";
+ $form .= gettext("NOTE: Changing this changes all child queues!");
+ $form .= gettext(" Beware you can lose information.");
+ $form .= "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
+ $form .= "</td><td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"bandwidth\" name=\"bandwidth\" value=\"";
+ $form .= $this->GetBandwidth() . "\" />";
+ $form .= "<select id=\"bandwidthtype\" name=\"bandwidthtype\" class=\"formselect\">";
+ $form .= "<option value=\"Kb\"";
+ if ($this->GetBwscale() == "Kb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">Kbit/s</option>";
+ $form .= "<option value=\"Mb\"";
+ if ($this->GetBwscale() == "Mb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">Mbit/s</option>";
+ $form .= "<option value=\"Gb\"";
+ if ($this->GetBwscale() == "Gb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">Gbit/s</option>";
+ $form .= "<option value=\"b\"";
+ if ($this->GetBwscale() == "b") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">Bit/s</option>";
+ $form .= "</select>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">Queue Limit</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
+ $form .= $this->GetQlimit();
+ $form .= "\" />";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">TBR Size</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<br /><input type=\"text\" id=\"tbrconfig\" name=\"tbrconfig\" value=\"";
+ $form .= $this->GetTbrConfig();
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">";
+ $form .= gettext("Adjusts the size, in bytes, of the token bucket regulator. "
+ . "If not specified, heuristics based on the interface "
+ . "bandwidth are used to determine the size.");
+ $form .= "</span></td></tr>";
+ $form .= "<input type=\"hidden\" id=\"interface\" name=\"interface\"";
+ $form .= " value=\"" . $this->GetInterface() . "\" />";
+ $form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"".$this->GetQname()."\" />";
+
+ return $form;
+ }
+
+ function update_altq_queue_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ /*
+ * Should call on each of it queues and subqueues
+ * the same function much like build_rules();
+ */
+ function wconfig() {
+ $cflink = &get_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['interface'] = $this->GetInterface();
+ $cflink['name'] = $this->GetQname();
+ $cflink['scheduler'] = $this->GetScheduler();
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['tbrconfig'] = trim($this->GetTbrConfig());
+ if (empty($cflink['tbrconfig'])) {
+ unset($cflink['tbrconfig']);
+ }
+ $cflink['enabled'] = $this->GetEnabled();
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ }
+
+}
+
+class priq_queue {
+ var $qname;
+ var $qinterface;
+ var $qlimit;
+ var $qpriority;
+ var $description;
+ var $isparent;
+ var $qbandwidth;
+ var $qbandwidthtype;
+ var $qdefault = "";
+ var $qrio = "";
+ var $qred = "";
+ var $qcodel = "";
+ var $qecn = "";
+ var $qack;
+ var $qenabled = "";
+ var $qparent;
+ var $link;
+ var $available_bw; /* in b/s */
+
+ /* This is here to help with form building and building rules/lists */
+ var $subqueues = array();
+
+ /* Accessor functions */
+ function GetAvailableBandwidth() {
+ return $this->available_bw;
+ }
+ function SetAvailableBandwidth($bw) {
+ $this->available_bw = $bw;
+ }
+ function SetLink($link) {
+ $this->link = $link;
+ }
+ function GetLink() {
+ return $this->link;
+ }
+ function &GetParent() {
+ return $this->qparent;
+ }
+ function SetParent(&$parent) {
+ $this->qparent = &$parent;
+ }
+ function GetEnabled() {
+ return $this->qenabled;
+ }
+ function SetEnabled($value) {
+ $this->qenabled = $value;
+ }
+ function CanHaveChildren() {
+ return false;
+ }
+ function CanBeDeleted() {
+ return true;
+ }
+ function GetQname() {
+ return $this->qname;
+ }
+ function SetQname($name) {
+ $this->qname = trim($name);
+ }
+ function GetBandwidth() {
+ return $this->qbandwidth;
+ }
+ function SetBandwidth($bandwidth) {
+ $this->qbandwidth = $bandwidth;
+ }
+ function GetInterface() {
+ return $this->qinterface;
+ }
+ function SetInterface($name) {
+ $this->qinterface = trim($name);
+ }
+ function GetQlimit() {
+ return $this->qlimit;
+ }
+ function SetQlimit($limit) {
+ $this->qlimit = $limit;
+ }
+ function GetQpriority() {
+ return $this->qpriority;
+ }
+ function SetQpriority($priority) {
+ $this->qpriority = $priority;
+ }
+ function GetDescription() {
+ return $this->description;
+ }
+ function SetDescription($str) {
+ $this->description = trim($str);
+ }
+ function GetFirstime() {
+ return $this->firsttime;
+ }
+ function SetFirsttime($number) {
+ $this->firsttime = $number;
+ }
+ function GetBwscale() {
+ return $this->qbandwidthtype;
+ }
+ function SetBwscale($scale) {
+ $this->qbandwidthtype = $scale;
+ }
+ function GetDefaultQueuePresent() {
+ if ($this->GetDefault()) {
+ return true;
+ }
+ if (!empty($this->subqueues)) {
+ foreach ($this->subqueues as $q) {
+ if ($q->GetDefault()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ function GetDefault() {
+ return $this->qdefault;
+ }
+ function SetDefault($value = false) {
+ $this->qdefault = $value;
+ }
+ function GetCodel() {
+ return $this->codel;
+ }
+ function SetCodel($codel = false) {
+ $this->codel = $codel;
+ }
+ function GetRed() {
+ return $this->qred;
+ }
+ function SetRed($red = false) {
+ $this->qred = $red;
+ }
+ function GetRio() {
+ return $this->qrio;
+ }
+ function SetRio($rio = false) {
+ $this->qrio = $rio;
+ }
+ function GetEcn() {
+ return $this->qecn;
+ }
+ function SetEcn($ecn = false) {
+ $this->qecn = $ecn;
+ }
+ function GetAck() {
+ return $this->qack;
+ }
+ function SetAck($ack = false) {
+ $this->qack = $ack;
+ }
+
+ function build_javascript() {
+ $javascript = "<script type=\"text/javascript\">";
+ $javascript .= "//<![CDATA[\n";
+ $javascript .= "function mySuspend() { \n";
+ $javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
+ $javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
+ $javascript .= "else if (document.all)\n";
+ $javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
+ $javascript .= "}\n";
+
+ $javascript .= "function myResume() {\n";
+ $javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
+ $javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
+ $javascript .= "else if (document.all)\n";
+ $javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
+ $javascript .= "}\n";
+ $javascript .= "//]]>";
+ $javascript .= "</script>";
+
+ return $javascript;
+ }
+
+ function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
+
+ /*
+ * Currently this will not be called unless we decide to clone a whole
+ * queue tree on the 'By Queues' view or support drag&drop on the tree/list
+ */
+ function copy_queue($interface, &$cflink) {
+
+ $cflink['name'] = $this->GetQname();
+ $cflink['interface'] = $interface;
+ $cflink['qlimit'] = $this->GetQlimit();
+ $cflink['priority'] = $this->GetQpriority();
+ $cflink['description'] = $this->GetDescription();
+ $cflink['enabled'] = $this->GetEnabled();
+ $cflink['default'] = $this->GetDefault();
+ $cflink['red'] = $this->GetRed();
+ $cflink['codel'] = $this->GetCodel();
+ $cflink['rio'] = $this->GetRio();
+ $cflink['ecn'] = $this->GetEcn();
+
+ if (is_array($this->subqueues)) {
+ $cflinkp['queue'] = array();
+ foreach ($this->subqueues as $q) {
+ $cflink['queue'][$q->GetQname()] = array();
+ $q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
+ }
+ }
+ }
+
+ function clean_queue($sched) {
+ clean_child_queues($sched, $this->GetLink());
+ if (is_array($this->subqueues)) {
+ foreach ($this->subqueues as $q) {
+ $q->clean_queue($sched);
+ }
+ }
+ }
+
+ function &get_queue_list(&$qlist) {
+
+ $qlist[$this->GetQname()] = & $this;
+ if (is_array($this->subqueues)) {
+ foreach ($this->subqueues as $queue) {
+ $queue->get_queue_list($qlist);
+ }
+ }
+ }
+
+ function delete_queue() {
+ unref_on_altq_queue_list($this->GetQname());
+ cleanup_queue_from_rules($this->GetQname());
+ unset_object_by_reference($this->GetLink());
+ }
+
+ function delete_all() {
+ if (count($this->subqueues)) {
+ foreach ($this->subqueues as $q) {
+ $q->delete_all();
+ unset_object_by_reference($q->GetLink());
+ unset($q);
+ }
+ unset($this->subqueues);
+ }
+ }
+
+ function &find_queue($interface, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+ }
+
+ function find_parentqueue($interface, $qname) { return; }
+
+ function validate_input($data, &$input_errors) {
+
+ $reqdfields[] = "name";
+ $reqdfieldsn[] = gettext("Name");
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
+ $input_errors[] = "Bandwidth must be an integer.";
+ }
+ if ($data['bandwidth'] < 0) {
+ $input_errors[] = "Bandwidth cannot be negative.";
+ }
+ if ($data['priority'] && (!is_numeric($data['priority']) ||
+ ($data['priority'] < 1) || ($data['priority'] > 15))) {
+ $input_errors[] = gettext("The priority must be an integer between 1 and 15.");
+ }
+ if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
+ $input_errors[] = gettext("Queue limit must be an integer");
+ }
+ if ($data['qlimit'] < 0) {
+ $input_errors[] = gettext("Queue limit must be positive");
+ }
+ if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname'])) {
+ $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
+ }
+ if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name'])) {
+ $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
+ }
+ $default = $this->GetDefault();
+ if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default)) {
+ $input_errors[] = gettext("Only one default queue per interface is allowed.");
+ }
+ }
+
+ function ReadConfig(&$q) {
+ if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
+ $this->SetQname($q['newname']);
+ } else if (!empty($q['newname'])) {
+ $this->SetQname($q['newname']);
+ } else if (isset($q['name'])) {
+ $this->SetQname($q['name']);
+ }
+ if (isset($q['interface'])) {
+ $this->SetInterface($q['interface']);
+ }
+ $this->SetBandwidth($q['bandwidth']);
+ if ($q['bandwidthtype'] <> "") {
+ $this->SetBwscale($q['bandwidthtype']);
+ }
+ if (!empty($q['qlimit'])) {
+ $this->SetQlimit($q['qlimit']);
+ } else {
+ $this->SetQlimit(""); // Default
+ }
+ if (!empty($q['priority'])) {
+ $this->SetQPriority($q['priority']);
+ } else {
+ $this->SetQpriority("");
+ }
+ if (!empty($q['description'])) {
+ $this->SetDescription($q['description']);
+ } else {
+ $this->SetDescription("");
+ }
+ if (!empty($q['red'])) {
+ $this->SetRed($q['red']);
+ } else {
+ $this->SetRed();
+ }
+ if (!empty($q['codel'])) {
+ $this->SetCodel($q['codel']);
+ } else {
+ $this->SetCodel();
+ }
+ if (!empty($q['rio'])) {
+ $this->SetRio($q['rio']);
+ } else {
+ $this->SetRio();
+ }
+ if (!empty($q['ecn'])) {
+ $this->SetEcn($q['ecn']);
+ } else {
+ $this->SetEcn();
+ }
+ if (!empty($q['default'])) {
+ $this->SetDefault($q['default']);
+ } else {
+ $this->SetDefault();
+ }
+ if (!empty($q['enabled'])) {
+ $this->SetEnabled($q['enabled']);
+ } else {
+ $this->SetEnabled("");
+ }
+ }
+
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
+ $tree .= "\" ";
+ $tmpvalue = $this->GetDefault();
+ if (!empty($tmpvalue)) {
+ $tree .= " class=\"navlnk\"";
+ }
+ $tree .= " >" . $this->GetQname() . "</a>";
+ /*
+ * Not needed here!
+ * if (is_array($queues) {
+ * $tree .= "<ul>";
+ * foreach ($q as $queues)
+ * $tree .= $queues['$q->GetName()']->build_tree();
+ * endforeach
+ * $tree .= "</ul>";
+ * }
+ */
+
+ $tree .= "</li>";
+
+ return $tree;
+ }
+
+ /* Should return something like:
+ * queue $qname on $qinterface bandwidth ....
+ */
+ function build_rules(&$default = false) {
+ $pfq_rule = " queue ". $this->qname;
+ if ($this->GetInterface()) {
+ $pfq_rule .= " on ".get_real_interface($this->GetInterface());
+ }
+ $tmpvalue = $this->GetQpriority();
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " priority ".$this->GetQpriority();
+ }
+ $tmpvalue = $this->GetQlimit();
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " qlimit " . $this->GetQlimit();
+ }
+ if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault() || $this->GetCodel()) {
+ $pfq_rule .= " priq ( ";
+ $tmpvalue = $this->GetRed();
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " red ";
+ }
+ $tmpvalue = $this->GetRio();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " rio ";
+ }
+ $tmpvalue = $this->GetEcn();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " ecn ";
+ }
+ $tmpvalue = $this->GetCodel();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " codel ";
+ }
+ $tmpvalue = $this->GetDefault();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $pfq_rule .= " default ";
+ $default = true;
+ }
+ $pfq_rule .= " ) ";
+ }
+
+ $pfq_rule .= " \n";
+
+ return $pfq_rule;
+ }
+
+ /*
+ * To return the html form to show to user
+ * for getting the parameters.
+ * Should do even for first time when the
+ * object is created and later when we may
+ * need to update it.
+ */
+ function build_form() {
+ $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
+ $form .= gettext("Enable/Disable");
+ $form .= "<br /></td><td class=\"vncellreq\">";
+ $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
+ if ($this->GetEnabled() == "on") {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue and its children") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr>";
+ $form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">";
+ $form .= gettext("Queue Name") . "</td><td width=\"78%\" class=\"vtable\">";
+ $form .= "<input name=\"newname\" type=\"text\" id=\"newname\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
+ $form .= htmlspecialchars($this->GetQname());
+ $form .= "\" />";
+ $form .= "<input name=\"name\" type=\"hidden\" id=\"name\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
+ $form .= htmlspecialchars($this->GetQname());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">" . gettext("Enter the name of the queue here. Do not use spaces and limit the size to 15 characters.");
+ $form .= "</span><br /></td>";
+ $form .= "</tr><tr>";
+ $form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Priority") . "</td>";
+ $form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"priority\" type=\"text\" id=\"priority\" size=\"5\" value=\"";
+ $form .= htmlspecialchars($this->GetQpriority());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">" . gettext("For hfsc, the range is 0 to 7. The default is 1. Hfsc queues with a higher priority are preferred in the case of overload.") . "</span></td>";
+ $form .= "</tr>";
+ $form .= "<tr>";
+ $form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Queue limit") . "</td>";
+ $form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"qlimit\" type=\"text\" id=\"qlimit\" size=\"8\" value=\"";
+ $form .= htmlspecialchars($this->GetQlimit());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">" . gettext("Queue limit in packets.");
+ $form .= "</span></td></tr>";
+ $form .= "<tr>";
+ $form .= "<td width=\"22%\" valign=\"middle\" class=\"vncell\">" . gettext("Scheduler options") . "</td>";
+ $form .= "<td width=\"78%\" class=\"vtable\">";
+ if (empty($this->subqueues)) {
+ if ($this->GetDefault()) {
+ $form .= "<input type=\"checkbox\" id=\"default\" checked=\"checked\" name=\"default\" value=\"default\"";
+ $form .= " /> " . gettext("Default queue") . "<br />";
+ } else {
+ $form .= "<input type=\"checkbox\" id=\"default\" name=\"default\" value=\"default\"";
+ $form .= " /> " . gettext("Default queue") . "<br />";
+ }
+ }
+ $form .= "<input type=\"checkbox\" id=\"red\" name=\"red\" value=\"red\" ";
+ $tmpvalue = $this->GetRed();
+ if (!empty($tmpvalue)) {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#red\">" . gettext("Random Early Detection") . "</a><br />";
+ $form .= "<input type=\"checkbox\" id=\"rio\" name=\"rio\" value=\"rio\"";
+ $tmpvalue = $this->GetRio();
+ if (!empty($tmpvalue)) {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#rio\">" . gettext("Random Early Detection In and Out") . "</a><br />";
+ $form .= "<input type=\"checkbox\" id=\"ecn\" name=\"ecn\" value=\"ecn\"";
+ $tmpvalue = $this->GetEcn();
+ if (!empty($tmpvalue)) {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#ecn\">" . gettext("Explicit Congestion Notification") . "</a><br />";
+ $form .= "<input type=\"checkbox\" id=\"codel\" name=\"codel\" value=\"codel\"";
+ $tmpvalue = $this->GetCodel();
+ if (!empty($tmpvalue)) {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /> <a target=\"_new\" href=\"http://www.bufferbloat.net/projects/codel/wiki\">" . gettext("Codel Active Queue") . "</a><br />";
+ $form .= "<span class=\"vexpl\"><br />" . gettext("Select options for this queue");
+ $form .= "</span></td></tr><tr>";
+ $form .= "<td width=\"22%\" class=\"vncellreq\">" . gettext("Description") . "</td>";
+ $form .= "<td width=\"78%\" class=\"vtable\">";
+ $form .= "<input type=\"text\" name=\"description\" size=\"40\" class=\"formfld unknown\" value=\"" . htmlspecialchars($this->GetDescription()) . "\" />";
+ $form .= "</td></tr>";
+ $form .= "<input type=\"hidden\" name=\"interface\" id=\"interface\"";
+ $form .= " value=\"".$this->GetInterface()."\" />";
+
+ return $form;
+ }
+
+ function build_shortform() {
+ /* XXX: Hacks in sight. Mostly layer violations! */
+ global $g, $altq_list_queues;
+ global $shaperIFlist;
+
+ $altq =& $altq_list_queues[$this->GetInterface()];
+ if ($altq) {
+ $scheduler = ": " . $altq->GetScheduler();
+ }
+ $form = "<tr><td width=\"20%\" class=\"vtable\">";
+ $form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=" . $this->GetQname()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .$scheduler."</a>";
+ $form .= "</td></tr>";
+ /*
+ * XXX: Hack in sight maybe fix with a class that wraps all
+ * of this layer violations
+ */
+ $form .= "<tr>";
+ $form .= "<td width=\"50%\" class=\"vncellreq\">";
+ $form .= gettext("Bandwidth:") . " " . $this->GetBandwidth().$this->GetBwscale();
+ $form .= "</td><td width=\"50%\"></td></tr>";
+ $tmpvalue = $this->GetQpriority();
+ if (!empty($tmpvalue)) {
+ $form .= "<tr><td width=\"20%\" class=\"vncellreq\">" .gettext("Priority: on") . " </td></tr>";
+ }
+ $tmpvalue = $this->GetDefault();
+ if (!empty($tmpvalue)) {
+ $form .= "<tr><td class=\"vncellreq\">" . gettext("Default: on") . " </td></tr>";
+ }
+ $form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
+ $form .= "<a href=\"firewall_shaper_queues.php?interface=";
+ $form .= $this->GetInterface() . "&amp;queue=";
+ $form .= $this->GetQname() . "&amp;action=delete\">";
+ $form .= "<img src=\"";
+ $form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
+ $form .= " width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("Delete queue from interface") . "\" alt=\"delete\" />";
+ $form .= "<span>" . gettext("Delete queue from interface") . "</span></a></td></tr>";
+
+ return $form;
+
+ }
+
+ function update_altq_queue_data(&$q) {
+ $this->ReadConfig($q);
+ }
+
+ function wconfig() {
+ $cflink =& get_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['interface'] = $this->GetInterface();
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = trim($this->GetQpriority());
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['description'] = trim($this->GetDescription());
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['enabled'] = trim($this->GetEnabled());
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = trim($this->GetDefault());
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['codel'] = trim($this->GetCodel());
+ if (empty($cflink['codel'])) {
+ unset($cflink['codel']);
+ }
+ $cflink['rio'] = trim($this->GetRio());
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ }
+}
+
+class hfsc_queue extends priq_queue {
+ /* realtime */
+ var $realtime;
+ var $r_m1;
+ var $r_d;
+ var $r_m2;
+ /* linkshare */
+ var $linkshare;
+ var $l_m1;
+ var $l_d;
+ var $l_m2;
+ /* upperlimit */
+ var $upperlimit;
+ var $u_m1;
+ var $u_d;
+ var $u_m2;
+
+ /*
+ * HFSC can have nested queues.
+ */
+ function CanHaveChildren() {
+ return true;
+ }
+ function GetRealtime() {
+ return $this->realtime;
+ }
+ function GetR_m1() {
+ return $this->r_m1;
+ }
+ function GetR_d() {
+ return $this->r_d;
+ }
+ function GetR_m2() {
+ return $this->r_m2;
+ }
+ function SetRealtime() {
+ $this->realtime = "on";
+ }
+ function DisableRealtime() {
+ $this->realtime = "";
+ }
+ function SetR_m1($value) {
+ $this->r_m1 = $value;
+ }
+ function SetR_d($value) {
+ $this->r_d = $value;
+ }
+ function SetR_m2($value) {
+ $this->r_m2 = $value;
+ }
+ function GetLinkshare() {
+ return $this->linkshare;
+ }
+ function DisableLinkshare() {
+ $this->linkshare = "";
+ }
+ function GetL_m1() {
+ return $this->l_m1;
+ }
+ function GetL_d() {
+ return $this->l_d;
+ }
+ function GetL_m2() {
+ return $this->l_m2;
+ }
+ function SetLinkshare() {
+ $this->linkshare = "on";
+ }
+ function SetL_m1($value) {
+ $this->l_m1 = $value;
+ }
+ function SetL_d($value) {
+ $this->l_d = $value;
+ }
+ function SetL_m2($value) {
+ $this->l_m2 = $value;
+ }
+ function GetUpperlimit() {
+ return $this->upperlimit;
+ }
+ function GetU_m1() {
+ return $this->u_m1;
+ }
+ function GetU_d() {
+ return $this->u_d;
+ }
+ function GetU_m2() {
+ return $this->u_m2;
+ }
+ function SetUpperlimit() {
+ $this->upperlimit = "on";
+ }
+ function DisableUpperlimit() {
+ $this->upperlimit = "";
+ }
+ function SetU_m1($value) {
+ $this->u_m1 = $value;
+ }
+ function SetU_d($value) {
+ $this->u_d = $value;
+ }
+ function SetU_m2($value) {
+ $this->u_m2 = $value;
+ }
+
+ function &add_queue($interface, &$qname, &$path, &$input_errors) {
+
+ if (!is_array($this->subqueues)) {
+ $this->subqueues = array();
+ }
+ $q =& new hfsc_queue();
+ $q->SetInterface($this->GetInterface());
+ $q->SetParent($this);
+ $q->ReadConfig($qname);
+ $q->validate_input($qname, $input_errors);
+ if (count($input_errors)) {
+ log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
+ return $q;
+ }
+
+ $q->SetEnabled("on");
+ $q->SetLink($path);
+ switch ($q->GetBwscale()) {
+ case "%":
+ $myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
+ break;
+ default:
+ $myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
+ break;
+ }
+ $q->SetAvailableBandwidth($myBw);
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
+
+ $this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
+ ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
+ if (is_array($qname['queue'])) {
+ foreach ($qname['queue'] as $key1 => $que) {
+ array_push($path, $key1);
+ $q->add_queue($q->GetInterface(), $que, $path, $input_errors);
+ array_pop($path);
+ }
+ }
+
+ return $q;
+ }
+
+ function copy_queue($interface, &$cflink) {
+
+ $cflink['name'] = $this->GetQname();
+ $cflink['interface'] = $interface;
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = trim($this->GetQpriority());
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['description'] = trim($this->GetDescription());
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = trim($this->GetEnabled());
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = trim($this->GetDefault());
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['rio'] = trim($this->GetRio());
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ if ($this->GetLinkshare() <> "") {
+ if ($this->GetL_m1() <> "") {
+ $cflink['linkshare1'] = $this->GetL_m1();
+ $cflink['linkshare2'] = $this->GetL_d();
+ $cflink['linkshare'] = "on";
+ } else {
+ unset($cflink['linkshare1']);
+ unset($cflink['linkshare2']);
+ unset($cflink['linkshare']);
+ }
+ if ($this->GetL_m2() <> "") {
+ $cflink['linkshare3'] = $this->GetL_m2();
+ $cflink['linkshare'] = "on";
+ } else {
+ unset($cflink['linkshare3']);
+ unset($cflink['linkshare']);
+ }
+ }
+ if ($this->GetRealtime() <> "") {
+ if ($this->GetR_m1() <> "") {
+ $cflink['realtime1'] = $this->GetR_m1();
+ $cflink['realtime2'] = $this->GetR_d();
+ $cflink['realtime'] = "on";
+ } else {
+ unset($cflink['realtime1']);
+ unset($cflink['realtime2']);
+ unset($cflink['realtime']);
+ }
+ if ($this->GetR_m2() <> "") {
+ $cflink['realtime3'] = $this->GetR_m2();
+ $cflink['realtime'] = "on";
+ } else {
+ unset($cflink['realtime3']);
+ unset($cflink['realtime']);
+ }
+ }
+ if ($this->GetUpperlimit() <> "") {
+ if ($this->GetU_m1() <> "") {
+ $cflink['upperlimit1'] = $this->GetU_m1();
+ $cflink['upperlimit2'] = $this->GetU_d();
+ $cflink['upperlimit'] = "on";
+ } else {
+ unset($cflink['upperlimit']);
+ unset($cflink['upperlimit1']);
+ unset($cflink['upperlimit2']);
+ }
+ if ($this->GetU_m2() <> "") {
+ $cflink['upperlimit3'] = $this->GetU_m2();
+ $cflink['upperlimit'] = "on";
+ } else {
+ unset($cflink['upperlimit3']);
+ unset($cflink['upperlimit']);
+ }
+ }
+
+ if (is_array($this->subqueues)) {
+ $cflinkp['queue'] = array();
+ foreach ($this->subqueues as $q) {
+ $cflink['queue'][$q->GetQname()] = array();
+ $q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
+ }
+ }
+ }
+
+ function delete_queue() {
+ unref_on_altq_queue_list($this->GetQname());
+ cleanup_queue_from_rules($this->GetQname());
+ $parent =& $this->GetParent();
+ foreach ($this->subqueues as $q) {
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
+ $q->delete_queue();
+ }
+ unset_object_by_reference($this->GetLink());
+ }
+
+ /*
+ * Should search even its children
+ */
+ function &find_queue($interface, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+
+ foreach ($this->subqueues as $q) {
+ $result =& $q->find_queue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function &find_parentqueue($interface, $qname) {
+ if ($this->subqueues[$qname]) {
+ return $this;
+ }
+ foreach ($this->subqueues as $q) {
+ $result = $q->find_parentqueue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function validate_input($data, &$input_errors) {
+ parent::validate_input($data, $input_errors);
+
+ $reqdfields[] = "bandwidth";
+ $reqdfieldsn[] = gettext("Bandwidth");
+ $reqdfields[] = "bandwidthtype";
+ $reqdfieldsn[] = gettext("Bandwidthtype");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
+ if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
+ $input_errors[] = gettext("Bandwidth must be an integer.");
+ }
+
+ if ($data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth cannot be negative.");
+ }
+
+ if ($data['bandwidthtype'] == "%") {
+ if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
+ }
+ }
+ /*
+ $parent =& $this->GetParent();
+ switch ($data['bandwidthtype']) {
+ case "%":
+ $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
+ default:
+ $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
+ break;
+ }
+ if ($parent->GetAvailableBandwidth() < $myBw) {
+ $input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
+ }
+ */
+ }
+
+ if ($data['upperlimit1'] <> "" && $data['upperlimit2'] == "") {
+ $input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
+ }
+ if ($data['upperlimit2'] <> "" && $data['upperlimit1'] == "") {
+ $input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
+ }
+ if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1'])) {
+ $input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
+ }
+ if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2'])) {
+ $input_errors[] = gettext("upperlimit d value needs to be numeric");
+ }
+ if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3'])) {
+ $input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
+ }
+
+ /*
+ if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
+ $bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
+ $bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
+ if (floatval($bw_1) < floatval($bw_2)) {
+ $input_errors[] = ("upperlimit m1 cannot be smaller than m2");
+ }
+
+ if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
+ $input_errors[] = ("upperlimit specification exceeds 80% of allowable allocation.");
+ }
+ }
+ */
+ if ($data['linkshare1'] <> "" && $data['linkshare2'] == "") {
+ $input_errors[] = gettext("linkshare service curve defined but missing (d) value");
+ }
+ if ($data['linkshare2'] <> "" && $data['linkshare1'] == "") {
+ $input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
+ }
+ if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1'])) {
+ $input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
+ }
+ if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2'])) {
+ $input_errors[] = gettext("linkshare d value needs to be numeric");
+ }
+ if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3'])) {
+ $input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
+ }
+ if ($data['realtime1'] <> "" && $data['realtime2'] == "") {
+ $input_errors[] = gettext("realtime service curve defined but missing (d) value");
+ }
+ if ($data['realtime2'] <> "" && $data['realtime1'] == "") {
+ $input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
+ }
+
+ /*
+ if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
+ $bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
+ $bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
+ if (floatval($bw_1) < floatval($bw_2)) {
+ $input_errors[] = ("linkshare m1 cannot be smaller than m2");
+ }
+
+ if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
+ $input_errors[] = ("linkshare specification exceeds 80% of allowable allocation.");
+ }
+ }
+ */
+
+ if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1'])) {
+ $input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
+ }
+ if ($data['realtime2'] <> "" && !is_numeric($data['realtime2'])) {
+ $input_errors[] = gettext("realtime d value needs to be numeric");
+ }
+ if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3'])) {
+ $input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
+ }
+
+ /*
+ if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
+ $bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
+ $bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
+ if (floatval($bw_1) < floatval($bw_2)) {
+ $input_errors[] = ("realtime m1 cannot be smaller than m2");
+ }
+
+ if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
+ $input_errors[] = ("realtime specification exceeds 80% of allowable allocation.");
+ }
+ }
+ */
+ }
+
+ function ReadConfig(&$cflink) {
+ if (!empty($cflink['linkshare'])) {
+ if (!empty($cflink['linkshare1'])) {
+ $this->SetL_m1($cflink['linkshare1']);
+ $this->SetL_d($cflink['linkshare2']);
+ $this->SetLinkshare();
+ } else {
+ $this->SetL_m1("");
+ $this->SetL_d("");
+ $this->DisableLinkshare();
+ }
+ if (!empty($cflink['linkshare3'])) {
+ $this->SetL_m2($cflink['linkshare3']);
+ $this->SetLinkshare();
+ }
+ } else {
+ $this->DisableLinkshare();
+ }
+ if (!empty($cflink['realtime'])) {
+ if (!empty($cflink['realtime1'])) {
+ $this->SetR_m1($cflink['realtime1']);
+ $this->SetR_d($cflink['realtime2']);
+ $this->SetRealtime();
+ } else {
+ $this->SetR_m1("");
+ $this->SetR_d("");
+ $this->DisableRealtime();
+ }
+ if (!empty($cflink['realtime3'])) {
+ $this->SetR_m2($cflink['realtime3']);
+ $this->SetRealtime();
+ }
+ } else {
+ $this->DisableRealtime();
+ }
+ if (!empty($cflink['upperlimit'])) {
+ if (!empty($cflink['upperlimit1'])) {
+ $this->SetU_m1($cflink['upperlimit1']);
+ $this->SetU_d($cflink['upperlimit2']);
+ $this->SetUpperlimit();
+ } else {
+ $this->SetU_m1("");
+ $this->SetU_d("");
+ $this->DisableUpperlimit();
+ }
+ if (!empty($cflink['upperlimit3'])) {
+ $this->SetU_m2($cflink['upperlimit3']);
+ $this->SetUpperlimit();
+ }
+ } else {
+ $this->DisableUpperlimit();
+ }
+ parent::ReadConfig($cflink);
+ }
+
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show";
+ $tree .= "\" ";
+ $tmpvalue = $this->GetDefault();
+ if (!empty($tmpvalue)) {
+ $tree .= " class=\"navlnk\"";
+ }
+ $tree .= " >" . $this->GetQname() . "</a>";
+ if (is_array($this->subqueues)) {
+ $tree .= "<ul>";
+ foreach ($this->subqueues as $q) {
+ $tree .= $q->build_tree();
+ }
+ $tree .= "</ul>";
+ }
+ $tree .= "</li>";
+ return $tree;
+ }
+
+ /* Even this should take children into consideration */
+ function build_rules(&$default = false) {
+
+ $pfq_rule = " queue ". $this->qname;
+ if ($this->GetInterface()) {
+ $pfq_rule .= " on ".get_real_interface($this->GetInterface());
+ }
+ if ($this->GetBandwidth() && $this->GetBwscale()) {
+ $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
+ }
+
+ $tmpvalue = $this->GetQlimit();
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " qlimit " . $this->GetQlimit();
+ }
+ if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetCodel() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
+ $pfq_rule .= " hfsc ( ";
+ $tmpvalue = $this->GetRed();
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " red ";
+ }
+
+ $tmpvalue = $this->GetRio();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " rio ";
+ }
+ $tmpvalue = $this->GetEcn();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " ecn ";
+ }
+ $tmpvalue = $this->GetCodel();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " codel ";
+ }
+ $tmpvalue = $this->GetDefault();
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " default ";
+ $default = true;
+ }
+
+ if ($this->GetRealtime() <> "") {
+ if ($comma) {
+ $pfq_rule .= " , ";
+ }
+ if ($this->GetR_m1() <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "") {
+ $pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
+ } else if ($this->GetR_m2() <> "") {
+ $pfq_rule .= " realtime " . $this->GetR_m2();
+ }
+ $comma = 1;
+ }
+ if ($this->GetLinkshare() <> "") {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "") {
+ $pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
+ } else if ($this->GetL_m2() <> "") {
+ $pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
+ }
+ $comma = 1;
+ }
+ if ($this->GetUpperlimit() <> "") {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "") {
+ $pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
+ } else if ($this->GetU_m2() <> "") {
+ $pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
+ }
+ }
+ $pfq_rule .= " ) ";
+ }
+ if (count($this->subqueues)) {
+ $i = count($this->subqueues);
+ $pfq_rule .= " { ";
+ foreach ($this->subqueues as $qkey => $qnone) {
+ if ($i > 1) {
+ $i--;
+ $pfq_rule .= " {$qkey}, ";
+ } else {
+ $pfq_rule .= " {$qkey} ";
+ }
+ }
+ $pfq_rule .= " } \n";
+ foreach ($this->subqueues as $q) {
+ $pfq_rule .= $q->build_rules($default);
+ }
+ }
+
+ $pfq_rule .= " \n";
+
+ return $pfq_rule;
+ }
+
+ function build_javascript() {
+ $javascript = parent::build_javascript();
+ $javascript .= "<script type=\"text/javascript\">";
+ $javascript .= "//<![CDATA[\n";
+ $javascript .= "function enable_realtime(enable_over) { \n";
+ $javascript .= "if (document.iform.realtime.checked || enable_over) { \n";
+ $javascript .= "document.iform.realtime1.disabled = 0;\n";
+ $javascript .= "document.iform.realtime2.disabled = 0;\n";
+ $javascript .= "document.iform.realtime3.disabled = 0;\n";
+ $javascript .= " } else { \n";
+ $javascript .= "document.iform.realtime1.disabled = 1;\n";
+ $javascript .= "document.iform.realtime2.disabled = 1;\n";
+ $javascript .= "document.iform.realtime3.disabled = 1;\n";
+ $javascript .= " } \n";
+ $javascript .= " } \n";
+ $javascript .= "function enable_linkshare(enable_over) { \n";
+ $javascript .= "if (document.iform.linkshare.checked || enable_over) { \n";
+ $javascript .= "document.iform.linkshare1.disabled = 0;\n";
+ $javascript .= "document.iform.linkshare2.disabled = 0;\n";
+ $javascript .= "document.iform.linkshare3.disabled = 0;\n";
+ $javascript .= " } else { \n";
+ $javascript .= "document.iform.linkshare1.disabled = 1;\n";
+ $javascript .= "document.iform.linkshare2.disabled = 1;\n";
+ $javascript .= "document.iform.linkshare3.disabled = 1;\n";
+ $javascript .= " } \n";
+ $javascript .= " } \n";
+ $javascript .= "function enable_upperlimit(enable_over) { \n";
+ $javascript .= "if (document.iform.upperlimit.checked || enable_over) { \n";
+ $javascript .= "document.iform.upperlimit1.disabled = 0;\n";
+ $javascript .= "document.iform.upperlimit2.disabled = 0;\n";
+ $javascript .= "document.iform.upperlimit3.disabled = 0;\n";
+ $javascript .= " } else { \n";
+ $javascript .= "document.iform.upperlimit1.disabled = 1;\n";
+ $javascript .= "document.iform.upperlimit2.disabled = 1;\n";
+ $javascript .= "document.iform.upperlimit3.disabled = 1;\n";
+ $javascript .= " } \n";
+
+ $javascript .= "} \n";
+ $javascript .= "//]]>";
+ $javascript .= "</script>";
+
+ return $javascript;
+ }
+
+ function build_form() {
+ $form = parent::build_form();
+ $form .= "<tr>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
+ $form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
+ $form .= htmlspecialchars($this->GetBandwidth());
+ $form .= "\" />";
+ $form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
+ $form .= "<option value=\"Gb\"";
+ if ($this->GetBwscale() == "Gb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Gbit/s") . "</option>";
+ $form .= "<option value=\"Mb\"";
+ if ($this->GetBwscale() == "Mb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Mbit/s") . "</option>";
+ $form .= "<option value=\"Kb\"";
+ if ($this->GetBwscale() == "Kb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Kbit/s") . "</option>";
+ $form .= "<option value=\"b\"";
+ if ($this->GetBwscale() == "b") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Bit/s") . "</option>";
+ $form .= "<option value=\"%\"";
+ if ($this->GetBwscale() == "%") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">%</option>";
+ $form .= "</select> <br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
+ $form .= "</span></td></tr>";
+ $form .= "<tr>";
+ $form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Service Curve (sc)") . "</td>";
+ $form .= "<td width=\"78%\" class=\"vtable\">";
+ $form .= "<table>";
+ $form .= "<tr><td>&nbsp;</td><td><center>m1</center></td><td><center>d</center></td><td><center><b>m2</b></center></td></tr>";
+ $form .= "<tr><td><input type=\"checkbox\" id=\"upperlimit\" name=\"upperlimit\"";
+ if ($this->GetUpperlimit()<> "") {
+ $form .= " checked=\"checked\" ";
+ }
+ $form .= "onchange=\"enable_upperlimit()\" /> " . gettext("Upperlimit:") . "</td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetU_m1());
+ $form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" ";
+ if ($this->GetUpperlimit() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetU_d());
+ $form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" ";
+ if ($this->GetUpperlimit() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetU_m2());
+ $form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" ";
+ if ($this->GetUpperlimit() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td>" . gettext("The maximum allowed bandwidth for the queue.") . "</td></tr>";
+ $form .= "<tr><td><input type=\"checkbox\" id=\"realtime\" name=\"realtime\"";
+ if ($this->GetRealtime() <> "") {
+ $form .= " checked=\"checked\" ";
+ }
+ $form .= "onchange=\"enable_realtime()\" /> " . gettext("Real time:") . "</td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetR_m1());
+ $form .= "\" id=\"realtime1\" name=\"realtime1\" ";
+ if ($this->GetRealtime() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetR_d());
+ $form .= "\" id=\"realtime2\" name=\"realtime2\" ";
+ if ($this->GetRealtime() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetR_m2());
+ $form .= "\" id=\"realtime3\" name=\"realtime3\" ";
+ if ($this->GetRealtime() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td>" . gettext("The minimum required bandwidth for the queue.") . "</td></tr>";
+ $form .= "<tr><td><input type=\"checkbox\" id=\"linkshare\" name=\"linkshare\"";
+ if ($this->GetLinkshare() <> "") {
+ $form .= " checked=\"checked\" ";
+ }
+ $form .= "onchange=\"enable_linkshare()\" /> " . gettext("Link share:") . "</td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetL_m1());
+ $form .= "\" id=\"linkshare1\" name=\"linkshare1\" ";
+ if ($this->GetLinkshare() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetL_d());
+ $form .= "\" id=\"linkshare2\" name=\"linkshare2\" ";
+ if ($this->GetLinkshare() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td><input size=\"6\" value=\"";
+ $form .= htmlspecialchars($this->GetL_m2());
+ $form .= "\" id=\"linkshare3\" name=\"linkshare3\" ";
+ if ($this->GetLinkshare() == "") {
+ $form .= " disabled=\"disabled\"";
+ }
+ $form .= " /></td><td>" . gettext("The bandwidth share of a backlogged queue - this overrides priority.") . "</td></tr>";
+ $form .= "</table><br />";
+ $form .= gettext("The format for service curve specifications is (m1, d, m2). m2 controls "
+ . "the bandwidth assigned to the queue. m1 and d are optional and can be "
+ . "used to control the initial bandwidth assignment. For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value "
+ . "given in m2.");
+ $form .= "</td>";
+ $form .= "</tr>";
+
+ return $form;
+ }
+
+ function update_altq_queue_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ function wconfig() {
+ $cflink =& get_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['interface'] = $this->GetInterface();
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = $this->GetQpriority();
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['description'] = $this->GetDescription();
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = $this->GetEnabled();
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = $this->GetDefault();
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['rio'] = $this->GetRio();
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ $cflink['codel'] = trim($this->GetCodel());
+ if (empty($cflink['codel'])) {
+ unset($cflink['codel']);
+ }
+ if ($this->GetLinkshare() <> "") {
+ if ($this->GetL_m1() <> "") {
+ $cflink['linkshare1'] = $this->GetL_m1();
+ $cflink['linkshare2'] = $this->GetL_d();
+ $cflink['linkshare'] = "on";
+ } else {
+ unset($cflink['linkshare']);
+ unset($cflink['linkshare1']);
+ unset($cflink['linkshare2']);
+ }
+ if ($this->GetL_m2() <> "") {
+ $cflink['linkshare3'] = $this->GetL_m2();
+ $cflink['linkshare'] = "on";
+ } else {
+ unset($cflink['linkshare']);
+ unset($cflink['linkshare3']);
+ }
+ } else {
+ unset($cflink['linkshare']);
+ unset($cflink['linkshare1']);
+ unset($cflink['linkshare2']);
+ unset($cflink['linkshare3']);
+ }
+ if ($this->GetRealtime() <> "") {
+ if ($this->GetR_m1() <> "") {
+ $cflink['realtime1'] = $this->GetR_m1();
+ $cflink['realtime2'] = $this->GetR_d();
+ $cflink['realtime'] = "on";
+ } else {
+ unset($cflink['realtime']);
+ unset($cflink['realtime1']);
+ unset($cflink['realtime2']);
+ }
+ if ($this->GetR_m2() <> "") {
+ $cflink['realtime3'] = $this->GetR_m2();
+ $cflink['realtime'] = "on";
+ } else {
+ unset($cflink['realtime']);
+ unset($cflink['realtime3']);
+ }
+ } else {
+ unset($cflink['realtime']);
+ unset($cflink['realtime1']);
+ unset($cflink['realtime2']);
+ unset($cflink['realtime3']);
+ }
+ if ($this->GetUpperlimit() <> "") {
+ if ($this->GetU_m1() <> "") {
+ $cflink['upperlimit1'] = $this->GetU_m1();
+ $cflink['upperlimit2'] = $this->GetU_d();
+ $cflink['upperlimit'] = "on";
+ } else {
+ unset($cflink['upperlimit']);
+ unset($cflink['upperlimit1']);
+ unset($cflink['upperlimit2']);
+ }
+ if ($this->GetU_m2() <> "") {
+ $cflink['upperlimit3'] = $this->GetU_m2();
+ $cflink['upperlimit'] = "on";
+ } else {
+ unset($cflink['upperlimit']);
+ unset($cflink['upperlimit3']);
+ }
+ } else {
+ unset($cflink['upperlimit']);
+ unset($cflink['upperlimit1']);
+ unset($cflink['upperlimit2']);
+ unset($cflink['upperlimit3']);
+ }
+ }
+}
+
+class cbq_queue extends priq_queue {
+ var $qborrow = "";
+
+ function GetBorrow() {
+ return $this->qborrow;
+ }
+ function SetBorrow($borrow) {
+ $this->qborrow = $borrow;
+ }
+ function CanHaveChildren() {
+ return true;
+ }
+
+ function &add_queue($interface, &$qname, &$path, &$input_errors) {
+
+ if (!is_array($this->subqueues)) {
+ $this->subqueues = array();
+ }
+ $q =& new cbq_queue();
+ $q->SetInterface($this->GetInterface());
+ $q->SetParent($this);
+ $q->ReadConfig($qname);
+ $q->validate_input($qname, $input_errors);
+ if (count($input_errors)) {
+ log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
+ return $q;
+ }
+ switch ($q->GetBwscale()) {
+ case "%":
+ $myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
+ break;
+ default:
+ $myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
+ break;
+ }
+ $q->SetAvailableBandwidth($myBw);
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
+
+ $q->SetEnabled("on");
+ $q->SetLink($path);
+ $this->subqueues[$q->GetQName()] = &$q;
+ ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
+ if (is_array($qname['queue'])) {
+ foreach ($qname['queue'] as $key1 => $que) {
+ array_push($path, $key1);
+ $q->add_queue($q->GetInterface(), $que, $path, $input_errors);
+ array_pop($path);
+ }
+ }
+
+ return $q;
+ }
+
+ function copy_queue($interface, &$cflink) {
+
+ $cflink['interface'] = $interface;
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($clink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = trim($this->GetQpriority());
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['description'] = trim($this->GetDescription());
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = trim($this->GetEnabled());
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = trim($this->GetDefault());
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['rio'] = trim($this->GetRio());
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ $cflink['borrow'] = trim($this->GetBorrow());
+ if (empty($cflink['borrow'])) {
+ unset($cflink['borrow']);
+ }
+ if (is_array($this->queues)) {
+ $cflinkp['queue'] = array();
+ foreach ($this->subqueues as $q) {
+ $cflink['queue'][$q->GetQname()] = array();
+ $q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
+ }
+ }
+ }
+
+ /*
+ * Should search even its children
+ */
+ function &find_queue($interface, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+ foreach ($this->subqueues as $q) {
+ $result =& $q->find_queue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function &find_parentqueue($interface, $qname) {
+ if ($this->subqueues[$qname]) {
+ return $this;
+ }
+ foreach ($this->subqueues as $q) {
+ $result = $q->find_parentqueue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function delete_queue() {
+ unref_on_altq_queue_list($this->GetQname());
+ cleanup_queue_from_rules($this->GetQname());
+ foreach ($this->subqueues as $q) {
+ $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
+ $q->delete_queue();
+ }
+ unset_object_by_reference($this->GetLink());
+ }
+
+ function validate_input($data, &$input_errors) {
+ parent::validate_input($data, $input_errors);
+
+ if ($data['priority'] > 7) {
+ $input_errors[] = gettext("Priority must be an integer between 1 and 7.");
+ }
+ $reqdfields[] = "bandwidth";
+ $reqdfieldsn[] = gettext("Bandwidth");
+ $reqdfields[] = "bandwidthtype";
+ $reqdfieldsn[] = gettext("Bandwidthtype");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
+ $input_errors[] = gettext("Bandwidth must be an integer.");
+ }
+
+
+ if ($data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth cannot be negative.");
+ }
+
+ if ($data['bandwidthtype'] == "%") {
+ if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
+ }
+ }
+
+/*
+ $parent =& $this->GetParent();
+ switch ($data['bandwidthtype']) {
+ case "%":
+ $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
+ break;
+ default:
+ $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
+ break;
+ }
+ if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
+ $input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
+ }
+ */
+ }
+
+ function ReadConfig(&$q) {
+ parent::ReadConfig($q);
+ if (!empty($q['borrow'])) {
+ $this->SetBorrow("on");
+ } else {
+ $this->SetBorrow("");
+ }
+ }
+
+ function build_javascript() {
+ return parent::build_javascript();
+ }
+
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
+ $tree .= "\" ";
+ $tmpvalue = trim($this->GetDefault());
+ if (!empty($tmpvalue)) {
+ $tree .= " class=\"navlnk\"";
+ }
+ $tree .= " >" . $this->GetQname() . "</a>";
+ if (is_array($this->subqueues)) {
+ $tree .= "<ul>";
+ foreach ($this->subqueues as $q) {
+ $tree .= $q->build_tree();
+ }
+ $tree .= "</ul>";
+ }
+ $tree .= "</li>";
+ return $tree;
+ }
+
+ /* Even this should take children into consideration */
+ function build_rules(&$default = false) {
+ $pfq_rule = "queue ". $this->qname;
+ if ($this->GetInterface()) {
+ $pfq_rule .= " on ".get_real_interface($this->GetInterface());
+ }
+ if ($this->GetBandwidth() && $this->GetBwscale()) {
+ $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
+ }
+ $tmpvalue = $this->GetQpriority();
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " priority " . $this->GetQpriority();
+ }
+ $tmpvalue = trim($this->GetQlimit());
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " qlimit " . $this->GetQlimit();
+ }
+ if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
+ $pfq_rule .= " cbq ( ";
+ $tmpvalue = trim($this->GetRed());
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " red ";
+ }
+ $tmpvalue = trim($this->GetCodel());
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " codel ";
+ }
+ $tmpvalue = trim($this->GetRio());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " rio ";
+ }
+ $tmpvalue = trim($this->GetEcn());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " ecn ";
+ }
+ $tmpvalue = trim($this->GetDefault());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " default ";
+ $default = true;
+ }
+ $tmpvalue = trim($this->GetBorrow());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= ", ";
+ }
+ $pfq_rule .= " borrow ";
+ }
+ $pfq_rule .= " ) ";
+ }
+ if (count($this->subqueues)) {
+ $i = count($this->subqueues);
+ $pfq_rule .= " { ";
+ foreach ($this->subqueues as $qkey => $qnone) {
+ if ($i > 1) {
+ $i--;
+ $pfq_rule .= " {$qkey}, ";
+ } else {
+ $pfq_rule .= " {$qkey} ";
+ }
+ }
+ $pfq_rule .= " } \n";
+ foreach ($this->subqueues as $q) {
+ $pfq_rule .= $q->build_rules($default);
+ }
+ }
+
+ $pfq_rule .= " \n";
+ return $pfq_rule;
+ }
+
+ function build_form() {
+ $form = parent::build_form();
+ $form .= "<tr>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
+ $form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
+ if ($this->GetBandwidth() > 0) {
+ $form .= htmlspecialchars($this->GetBandwidth());
+ }
+ $form .= "\" />";
+ $form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
+ $form .= "<option value=\"Gb\"";
+ if ($this->GetBwscale() == "Gb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Gbit/s") . "</option>";
+ $form .= "<option value=\"Mb\"";
+ if ($this->GetBwscale() == "Mb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Mbit/s") . "</option>";
+ $form .= "<option value=\"Kb\"";
+ if ($this->GetBwscale() == "Kb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Kbit/s") . "</option>";
+ $form .= "<option value=\"b\"";
+ if ($this->GetBwscale() == "b") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Bit/s") . "</option>";
+ $form .= "<option value=\"%\"";
+ if ($this->GetBwscale() == "%") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">%</option>";
+ $form .= "</select> <br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
+ $form .= "</span></td></tr>";
+ $form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
+ $form .= "<td class=\"vtable\"><input type=\"checkbox\" id=\"borrow\" name=\"borrow\"";
+ if ($this->GetBorrow() == "on") {
+ $form .= " checked=\"checked\" ";
+ }
+ $form .= " /> " . gettext("Borrow from other queues when available") . "<br /></td></tr>";
+
+ return $form;
+ }
+
+ function update_altq_queue_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ function wconfig() {
+ $cflink =& get_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['interface'] = $this->GetInterface();
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = $this->GetQpriority();
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['description'] = $this->GetDescription();
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = trim($this->GetEnabled());
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = trim($this->GetDefault());
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['rio'] = trim($this->GetRio());
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ $cflink['codel'] = trim($this->GetCodel());
+ if (empty($cflink['codel'])) {
+ unset($cflink['codel']);
+ }
+ $cflink['borrow'] = trim($this->GetBorrow());
+ if (empty($cflink['borrow'])) {
+ unset($cflink['borrow']);
+ }
+ }
+}
+
+class fairq_queue extends priq_queue {
+ var $hogs;
+ var $buckets;
+
+ function GetBuckets() {
+ return $this->buckets;
+ }
+ function SetBuckets($buckets) {
+ $this->buckets = $buckets;
+ }
+ function GetHogs() {
+ return $this->hogs;
+ }
+ function SetHogs($hogs) {
+ $this->hogs = $hogs;
+ }
+ function CanHaveChildren() {
+ return false;
+ }
+
+
+ function copy_queue($interface, &$cflink) {
+ $cflink['interface'] = $interface;
+ $cflink['qlimit'] = $this->GetQlimit();
+ $cflink['priority'] = $this->GetQpriority();
+ $cflink['name'] = $this->GetQname();
+ $cflink['description'] = $this->GetDescription();
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = $this->GetEnabled();
+ $cflink['default'] = $this->GetDefault();
+ $cflink['red'] = $this->GetRed();
+ $cflink['rio'] = $this->GetRio();
+ $cflink['ecn'] = $this->GetEcn();
+ $cflink['buckets'] = $this->GetBuckets();
+ $cflink['hogs'] = $this->GetHogs();
+ }
+
+ /*
+ * Should search even its children
+ */
+ function &find_queue($interface, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+ }
+
+ function find_parentqueue($interface, $qname) { return; }
+
+ function delete_queue() {
+ unref_on_altq_queue_list($this->GetQname());
+ cleanup_queue_from_rules($this->GetQname());
+ unset_object_by_reference($this->GetLink());
+ }
+
+ function validate_input($data, &$input_errors) {
+ parent::validate_input($data, $input_errors);
+
+ if ($data['priority'] > 255) {
+ $input_errors[] = gettext("Priority must be an integer between 1 and 255.");
+ }
+ $reqdfields[] = "bandwidth";
+ $reqdfieldsn[] = gettext("Bandwidth");
+ $reqdfields[] = "bandwidthtype";
+ $reqdfieldsn[] = gettext("Bandwidthtype");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
+ $input_errors[] = gettext("Bandwidth must be an integer.");
+ }
+
+
+ if ($data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth cannot be negative.");
+ }
+
+
+ if ($data['bandwidthtype'] == "%") {
+ if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
+ $input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
+ }
+ }
+
+/*
+ $parent =& $this->GetParent();
+ switch ($data['bandwidthtype']) {
+ case "%":
+ $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
+ default:
+ $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
+ break;
+ }
+ if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
+ $input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
+ }
+*/
+ }
+
+ function ReadConfig(&$q) {
+ parent::ReadConfig($q);
+ if (!empty($q['buckets'])) {
+ $this->SetBuckets($q['buckets']);
+ } else {
+ $this->SetBuckets("");
+ }
+ if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) {
+ $this->SetHogs($q['hogs']);
+ } else {
+ $this->SetHogs("");
+ }
+ }
+
+ function build_javascript() {
+ return parent::build_javascript();
+ }
+
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper.php?interface=" .
+ $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
+ $tree .= "\" ";
+ $tmpvalue = trim($this->GetDefault());
+ if (!empty($tmpvalue)) {
+ $tree .= " class=\"navlnk\"";
+ }
+ $tree .= " >" . $this->GetQname() . "</a>";
+ $tree .= "</li>";
+ return $tree;
+ }
+
+ /* Even this should take children into consideration */
+ function build_rules(&$default = false) {
+ $pfq_rule = "queue ". $this->qname;
+ if ($this->GetInterface()) {
+ $pfq_rule .= " on ".get_real_interface($this->GetInterface());
+ }
+ if ($this->GetBandwidth() && $this->GetBwscale()) {
+ $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
+ }
+ $tmpvalue = trim($this->GetQpriority());
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " priority " . $this->GetQpriority();
+ }
+ $tmpvalue = trim($this->GetQlimit());
+ if (!empty($tmpvalue)) {
+ $pfq_rule .= " qlimit " . $this->GetQlimit();
+ }
+ if ($this->GetDefault() || $this->GetRed() || $this->GetRio() ||
+ $this->GetEcn() || $this->GetBuckets() || $this->GetHogs() || $this->GetCodel()) {
+ $pfq_rule .= " fairq ( ";
+ $tmpvalue = trim($this->GetRed());
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " red ";
+ }
+ $tmpvalue = trim($this->GetCodel());
+ if (!empty($tmpvalue)) {
+ $comma = 1;
+ $pfq_rule .= " codel ";
+ }
+ $tmpvalue = trim($this->GetRio());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " rio ";
+ }
+ $tmpvalue = trim($this->GetEcn());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " ecn ";
+ }
+ $tmpvalue = trim($this->GetDefault());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= " ,";
+ }
+ $comma = 1;
+ $pfq_rule .= " default ";
+ $default = true;
+ }
+ $tmpvalue = trim($this->GetBuckets());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= ", ";
+ }
+ $pfq_rule .= " buckets " . $this->GetBuckets() . " ";
+ }
+ $tmpvalue = trim($this->GetHogs());
+ if (!empty($tmpvalue)) {
+ if ($comma) {
+ $pfq_rule .= ", ";
+ }
+ $pfq_rule .= " hogs " . $this->GetHogs() . " ";
+ }
+ $pfq_rule .= " ) ";
+ }
+
+ $pfq_rule .= " \n";
+ return $pfq_rule;
+ }
+
+ function build_form() {
+ $form = parent::build_form();
+ $form .= "<tr>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
+ $form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
+ if ($this->GetBandwidth() > 0) {
+ $form .= htmlspecialchars($this->GetBandwidth());
+ }
+ $form .= "\" />";
+ $form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
+ $form .= "<option value=\"Gb\"";
+ if ($this->GetBwscale() == "Gb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Gbit/s") . "</option>";
+ $form .= "<option value=\"Mb\"";
+ if ($this->GetBwscale() == "Mb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Mbit/s") . "</option>";
+ $form .= "<option value=\"Kb\"";
+ if ($this->GetBwscale() == "Kb") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Kbit/s") . "</option>";
+ $form .= "<option value=\"b\"";
+ if ($this->GetBwscale() == "b") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Bit/s") . "</option>";
+ $form .= "<option value=\"%\"";
+ if ($this->GetBwscale() == "%") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">%</option>";
+ $form .= "</select> <br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
+ $form .= "</span></td></tr>";
+ $form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
+ $form .= "<td class=\"vtable\"><table><tr><td>";
+ $form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
+ $tmpvalue = trim($this->GetBuckets());
+ if (!empty($tmpvalue)) {
+ $form .= $this->GetBuckets();
+ }
+ $form .= "\" /> " . gettext("Number of buckets available.") . "<br /></td></tr>";
+ $form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
+ $tmpvalue = trim($this->GetHogs());
+ if (!empty($tmpvalue)) {
+ $form .= $this->GetHogs();
+ }
+ $form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br /></td></tr>";
+ $form .= "</table></td></tr>";
+ return $form;
+ }
+
+ function update_altq_queue_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ function wconfig() {
+ $cflink =& get_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['interface'] = $this->GetInterface();
+ $cflink['qlimit'] = trim($this->GetQlimit());
+ if (empty($cflink['qlimit'])) {
+ unset($cflink['qlimit']);
+ }
+ $cflink['priority'] = trim($this->GetQpriority());
+ if (empty($cflink['priority'])) {
+ unset($cflink['priority']);
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['description'] = trim($this->GetDescription());
+ if (empty($cflink['description'])) {
+ unset($cflink['description']);
+ }
+ $cflink['bandwidth'] = $this->GetBandwidth();
+ $cflink['bandwidthtype'] = $this->GetBwscale();
+ $cflink['enabled'] = $this->GetEnabled();
+ if (empty($cflink['enabled'])) {
+ unset($cflink['enabled']);
+ }
+ $cflink['default'] = trim($this->GetDefault());
+ if (empty($cflink['default'])) {
+ unset($cflink['default']);
+ }
+ $cflink['red'] = trim($this->GetRed());
+ if (empty($cflink['red'])) {
+ unset($cflink['red']);
+ }
+ $cflink['rio'] = trim($this->GetRio());
+ if (empty($cflink['rio'])) {
+ unset($cflink['rio']);
+ }
+ $cflink['ecn'] = trim($this->GetEcn());
+ if (empty($cflink['ecn'])) {
+ unset($cflink['ecn']);
+ }
+ $cflink['codel'] = trim($this->GetCodel());
+ if (empty($cflink['codel'])) {
+ unset($cflink['codel']);
+ }
+ $cflink['buckets'] = trim($this->GetBuckets());
+ if (empty($cflink['buckets'])) {
+ unset($cflink['buckets']);
+ }
+ $cflink['hogs'] = trim($this->GetHogs());
+ if (empty($cflink['hogs'])) {
+ unset($cflink['hogs']);
+ }
+ }
+}
+
+
+/*
+ * dummynet(4) wrappers.
+ */
+
+
+/*
+ * List of respective objects!
+ */
+$dummynet_pipe_list = array();
+
+class dummynet_class {
+ var $qname;
+ var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
+ var $qlimit;
+ var $description;
+ var $qenabled;
+ var $link;
+ var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
+ var $plr;
+
+ var $buckets;
+ /* mask parameters */
+ var $mask;
+ var $noerror;
+
+ /* Accessor functions */
+ function SetLink($link) {
+ $this->link = $link;
+ }
+ function GetLink() {
+ return $this->link;
+ }
+ function GetMask() {
+ if (!isset($this->mask["type"])) {
+ $this->mask["type"] = "none";
+ }
+ return $this->mask;
+ }
+ function SetMask($mask) {
+ $this->mask = $mask;
+ }
+ function &GetParent() {
+ return $this->qparent;
+ }
+ function SetParent(&$parent) {
+ $this->qparent = &$parent;
+ }
+ function GetEnabled() {
+ return $this->qenabled;
+ }
+ function SetEnabled($value) {
+ $this->qenabled = $value;
+ }
+ function CanHaveChildren() {
+ return false;
+ }
+ function CanBeDeleted() {
+ return true;
+ }
+ function GetQname() {
+ return $this->qname;
+ }
+ function SetQname($name) {
+ $this->qname = trim($name);
+ }
+ function GetQlimit() {
+ return $this->qlimit;
+ }
+ function SetQlimit($limit) {
+ $this->qlimit = $limit;
+ }
+ function GetDescription() {
+ return $this->description;
+ }
+ function SetDescription($str) {
+ $this->description = trim($str);
+ }
+ function GetFirstime() {
+ return $this->firsttime;
+ }
+ function SetFirsttime($number) {
+ $this->firsttime = $number;
+ }
+ function GetBuckets() {
+ return $this->buckets;
+ }
+ function SetBuckets($buckets) {
+ $this->buckets = $buckets;
+ }
+ function SetNumber($number) {
+ $this->qnumber = $number;
+ }
+ function GetNumber() {
+ return $this->qnumber;
+ }
+ function GetPlr() {
+ return $this->plr;
+ }
+ function SetPlr($plr) {
+ $this->plr = $plr;
+ }
+
+ function build_javascript() {
+ $javascript .= "<script type=\"text/javascript\">\n";
+ $javascript .= "//<![CDATA[\n";
+ $javascript .= "function enable_maskbits(enable_over) {\n";
+ $javascript .= "var e = document.getElementById(\"mask\");\n";
+ $javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
+ $javascript .= "document.iform.maskbits.disabled = 1;\n";
+ $javascript .= "document.iform.maskbits.value = \"\";\n";
+ $javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
+ $javascript .= "document.iform.maskbitsv6.value = \"\";\n";
+ $javascript .= "} else {\n";
+ $javascript .= "document.iform.maskbits.disabled = 0;\n";
+ $javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
+ $javascript .= "}}\n";
+ $javascript .= "//]]>\n";
+ $javascript .= "</script>\n";
+ return $javascript;
+ }
+
+ function validate_input($data, &$input_errors) {
+ $reqdfields[] = "bandwidth";
+ $reqdfieldsn[] = gettext("Bandwidth");
+ /*$reqdfields[] = "burst";
+ $reqdfieldsn[] = gettext("Burst"); */
+ $reqdfields[] = "bandwidthtype";
+ $reqdfieldsn[] = gettext("Bandwidthtype");
+ $reqdfields[] = "newname";
+ $reqdfieldsn[] = gettext("Name");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if ($data['plr'] && (!is_numeric($data['plr']) ||
+ ($data['plr'] < 0) || ($data['plr'] > 1))) {
+ $input_errors[] = gettext("Plr must be a value between 0 and 1.");
+ }
+ if ($data['buckets'] && (!is_numeric($data['buckets']) ||
+ ($data['buckets'] < 16) || ($data['buckets'] > 65535))) {
+ $input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
+ }
+ if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
+ $input_errors[] = gettext("Queue limit must be an integer");
+ }
+ if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname'])) {
+ $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
+ }
+ if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name'])) {
+ $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
+ }
+ if (isset($data['maskbits']) && ($data['maskbits'] <> "")) {
+ if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32)) {
+ $input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
+ }
+ }
+ if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> "")) {
+ if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128)) {
+ $input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
+ }
+ }
+ }
+
+ function build_mask_rules(&$pfq_rule) {
+ $mask = $this->GetMask();
+ if (!empty($mask['type'])) {
+ if ($mask['type'] <> 'none') {
+ $pfq_rule .= " mask";
+ }
+ switch ($mask['type']) {
+ case 'srcaddress':
+ if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
+ $pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
+ } else {
+ $pfq_rule .= " src-ip6 /128";
+ }
+ if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
+ $pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
+ } else {
+ $pfq_rule .= " src-ip 0xffffffff";
+ }
+ break;
+ case 'dstaddress':
+ if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
+ $pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
+ } else {
+ $pfq_rule .= " dst-ip6 /128";
+ }
+ if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
+ $pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
+ } else {
+ $pfq_rule .= " dst-ip 0xffffffff";
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+class dnpipe_class extends dummynet_class {
+ var $delay;
+ var $qbandwidth = array();
+ var $qbandwidthtype;
+
+ /* This is here to help on form building and building rules/lists */
+ var $subqueues = array();
+
+ function CanHaveChildren() {
+ return true;
+ }
+ function SetDelay($delay) {
+ $this->delay = $delay;
+ }
+ function GetDelay() {
+ return $this->delay;
+ }
+ function delete_queue() {
+ cleanup_dnqueue_from_rules($this->GetQname());
+ foreach ($this->subqueues as $q) {
+ $q->delete_queue();
+ }
+ unset_dn_object_by_reference($this->GetLink());
+ @pfSense_pipe_action("pipe delete " . $this->GetNumber());
+ }
+ function GetBandwidth() {
+ return $this->qbandwidth;
+ }
+ function SetBandwidth($bandwidth) {
+ $this->qbandwidth = $bandwidth;
+ }
+ function GetBurst() {
+ return $this->qburst;
+ }
+ function SetBurst($burst) {
+ $this->qburst = $burst;
+ }
+
+ function &add_queue($interface, &$queue, &$path, &$input_errors) {
+
+ if (!is_array($this->subqueues)) {
+ $this->subqueues = array();
+ }
+
+ $q =& new dnqueue_class();
+ $q->SetLink($path);
+ $q->SetEnabled("on");
+ $q->SetPipe($this->GetQname());
+ $q->SetParent($this);
+ $q->ReadConfig($queue);
+ $q->validate_input($queue, $input_errors);
+ if (count($input_errors)) {
+ log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
+ return $q;
+ }
+ $number = dnqueue_find_nextnumber();
+ $q->SetNumber($number);
+ $this->subqueues[$q->GetQname()] = &$q;
+
+ return $q;
+ }
+
+ function &get_queue_list(&$q = null) {
+ $qlist = array();
+
+ $qlist[$this->GetQname()] = $this->GetNumber();
+ if (is_array($this->subqueues)) {
+ foreach ($this->subqueues as $queue) {
+ $queue->get_queue_list($qlist);
+ }
+ }
+ return $qlist;
+ }
+
+ /*
+ * Should search even its children
+ */
+ function &find_queue($pipe, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ }
+ foreach ($this->subqueues as $q) {
+ $result =& $q->find_queue("", $qname);
+ if ($result) {
+ return $result;
+ }
+ }
+ }
+
+ function &find_parentqueue($pipe, $qname) {
+ return NULL;
+ }
+
+ function validate_input($data, &$input_errors) {
+ parent::validate_input($data, $input_errors);
+
+ $schedule = 0;
+ $schedulenone = 0;
+ $entries = 0;
+ /* XXX: Really no better way? */
+ for ($i = 0; $i < 2900; $i++) {
+ if (!empty($data["bwsched{$i}"])) {
+ if ($data["bwsched{$i}"] != "none") {
+ $schedule++;
+ } else {
+ $schedulenone++;
+ }
+ }
+ if (!empty($data["bandwidth{$i}"])) {
+ if (!is_numeric($data["bandwidth{$i}"])) {
+ $input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
+ } else if (($data["burst{$i}"] != "") && (!is_numeric($data["burst{$i}"]))) {
+ $input_errors[] = sprintf(gettext("Burst for schedule %s must be an integer."), $data["bwsched{$i}"]);
+ } else {
+ $entries++;
+ }
+ }
+ }
+ if ($schedule == 0 && $entries > 1) {
+ $input_errors[] = gettext("You need to specify a schedule for every additional entry");
+ }
+ if ($schedulenone > 0 && $entries > 1) {
+ $input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
+ }
+ if ($entries == 0) {
+ $input_errors[] = gettext("At least one bw specification is necessary");
+ }
+ if ($data['delay'] && (!is_numeric($data['delay']))) {
+ $input_errors[] = gettext("Delay must be an integer.");
+ }
+ }
+
+ function ReadConfig(&$q) {
+ if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
+ $this->SetQname($q['newname']);
+ } else if (!empty($q['newname'])) {
+ $this->SetQname($q['newname']);
+ } else {
+ $this->SetQname($q['name']);
+ }
+ $this->SetNumber($q['number']);
+
+ if (!empty($_POST)) {
+ $bandwidth = array();
+ /* XXX: Really no better way? */
+ for ($i = 0; $i < 2900; $i++) {
+ if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
+ $bw = array();
+ $bw['bw'] = $q["bandwidth{$i}"];
+ $bw['burst'] = $q["burst{$i}"];
+ if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"]) {
+ $bw['bwscale'] = $q["bwtype{$i}"];
+ }
+ if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"]) {
+ $bw['bwsched'] = $q["bwsched{$i}"];
+ }
+ $bandwidth[] = $bw;
+ }
+ }
+ $this->SetBandwidth($bandwidth);
+ }
+
+ if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
+ $this->SetBandwidth($q['bandwidth']['item']);
+ $this->SetBurst($q['burst']['item']);
+ }
+
+ if (isset($q['qlimit']) && $q['qlimit'] <> "") {
+ $this->SetQlimit($q['qlimit']);
+ } else {
+ $this->SetQlimit("");
+ }
+ if (isset($q['mask']) && $q['mask'] <> "") {
+ $masktype = $q['mask'];
+ } else {
+ $masktype = "";
+ }
+ if (isset($q['maskbits']) && $q['maskbits'] <> "") {
+ $maskbits = $q['maskbits'];
+ } else {
+ $maskbits = "";
+ }
+ if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
+ $maskbitsv6 = $q['maskbitsv6'];
+ } else {
+ $maskbitsv6 = "";
+ }
+ $this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
+ if (isset($q['buckets']) && $q['buckets'] <> "") {
+ $this->SetBuckets($q['buckets']);
+ } else {
+ $this->SetBuckets("");
+ }
+ if (isset($q['plr']) && $q['plr'] <> "") {
+ $this->SetPlr($q['plr']);
+ } else {
+ $this->SetPlr("");
+ }
+ if (isset($q['delay']) && $q['delay'] <> "") {
+ $this->SetDelay($q['delay']);
+ } else {
+ $this->SetDelay(0);
+ }
+ if (isset($q['description']) && $q['description'] <> "") {
+ $this->SetDescription($q['description']);
+ } else {
+ $this->SetDescription("");
+ }
+ $this->SetEnabled($q['enabled']);
+
+ }
+
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
+ $tree .= $this->GetQname() . "</a>";
+ if (is_array($this->subqueues)) {
+ $tree .= "<ul>";
+ foreach ($this->subqueues as $q) {
+ $tree .= $q->build_tree();
+ }
+ $tree .= "</ul>";
+ }
+ $tree .= "</li>";
+
+ return $tree;
+ }
+
+ function build_rules() {
+ global $config, $time_based_rules;
+
+ if ($this->GetEnabled() == "") {
+ return;
+ }
+
+ $pfq_rule = "\npipe ". $this->GetNumber() . " config ";
+ $found = false;
+ $bandwidth = $this->GetBandwidth();
+ if (is_array($bandwidth)) {
+ foreach ($bandwidth as $bw) {
+ if ($bw['bwsched'] != "none") {
+ $time_based_rules = true;
+ if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
+ foreach ($config['schedules']['schedule'] as $schedule) {
+ if ($bw['bwsched'] == $schedule['name']) {
+ if (filter_get_time_based_rule_status($schedule)) {
+ $pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
+ if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
+ $pfq_rule .= " burst ".trim($bw['burst']);
+ }
+ $found = true;
+ break;
+ }
+ }
+ }
+ } else {
+ $pfq_rule .= " bw 0";
+ $found = true;
+ break;
+ }
+ } else {
+ $pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
+ if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
+ $pfq_rule .= " burst ".trim($bw['burst']);
+ }
+ $found = true;
+ break;
+ }
+ }
+ if ($found == false) {
+ $pfq_rule .= " bw 0";
+ }
+ } else {
+ $pfq_rule .= " bw 0";
+ }
+
+ if ($this->GetQlimit()) {
+ $pfq_rule .= " queue " . $this->GetQlimit();
+ }
+ if ($this->GetPlr()) {
+ $pfq_rule .= " plr " . $this->GetPlr();
+ }
+ if ($this->GetBuckets()) {
+ $pfq_rule .= " buckets " . $this->GetBuckets();
+ }
+ if ($this->GetDelay()) {
+ $pfq_rule .= " delay " . $this->GetDelay();
+ }
+ $this->build_mask_rules($pfq_rule);
+
+ $pfq_rule .= "\n";
+
+ if (!empty($this->subqueues) && count($this->subqueues) > 0) {
+ foreach ($this->subqueues as $q) {
+ $pfq_rule .= $q->build_rules();
+ }
+ }
+ $pfq_rule .= " \n";
+
+ return $pfq_rule;
+ }
+
+ function update_dn_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ function build_javascript() {
+ global $g, $config;
+
+ $javasr = parent::build_javascript();
+
+ //build list of schedules
+ $schedules = "<option value='none'>none</option>";
+ if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
+ foreach ($config['schedules']['schedule'] as $schedule) {
+ if ($schedule['name'] <> "") {
+ $schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
+ }
+ }
+ }
+ $bwopt = "";
+ foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
+ $bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
+ }
+
+ $javasr .= <<<EOD
+<script type='text/javascript'>
+//<![CDATA[
+var addBwRowTo = (function() {
+ return (function (tableId) {
+ var d, tbody, tr, td;
+ d = document;
+ tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
+ tr = d.createElement("tr");
+ td = d.createElement("td");
+ td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bandwidth_row-" + totalrows + "' /><input size='10' type='text' class='formfld unknown' name='bandwidth" + totalrows + "' id='bandwidth" + totalrows + "' />";
+ tr.appendChild(td);
+ //td = d.createElement("td");
+ //td.innerHTML="<input type='hidden' value='" + totalrows +"' name='burst_row-" + totalrows + "' /><input size='10' type='text' class='formfld unknown' name='burst" + totalrows + "' id='burst" + totalrows + "' />";
+ //tr.appendChild(td);
+ td = d.createElement("td");
+ td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
+ tr.appendChild(td);
+ td = d.createElement("td");
+ td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
+ tr.appendChild(td);
+ td = d.createElement("td");
+ td.rowSpan = "1";
+ td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" alt="remove" /></a>';
+ tr.appendChild(td);
+ tbody.appendChild(tr);
+ totalrows++;
+ });
+})();
+
+function removeBwRow(el) {
+ var cel;
+ while (el && el.nodeName.toLowerCase() != "tr") {
+ el = el.parentNode;
+ if (el && el.parentNode) {
+ cel = el.getElementsByTagName("td").item(0);
+ el.parentNode.removeChild(el);
+ }
+ }
+}
+//]]>
+</script>
+
+EOD;
+
+ return $javasr;
+ }
+
+ function build_form() {
+ global $g, $config;
+
+ //build list of schedules
+ $schedules = array();
+ $schedules[] = "none";//leave none to leave rule enabled all the time
+ if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
+ foreach ($config['schedules']['schedule'] as $schedule) {
+ if ($schedule['name'] <> "") {
+ $schedules[] = $schedule['name'];
+ }
+ }
+ }
+
+ $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
+ $form .= gettext("Enable");
+ $form .= "</td><td class=\"vncellreq\">";
+ $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
+ if ($this->GetEnabled() == "on") {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /><span class=\"vexpl\"> " . gettext("Enable limiter and its children") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
+ $form .= $this->GetQname()."\" />";
+ $form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
+ $form .= $this->GetQname()."\" />";
+ if ($this->GetNumber() > 0) {
+ $form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
+ $form .= $this->GetNumber()."\" />";
+ }
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
+ $bandwidth = $this->GetBandwidth();
+ $form .= "</td><td class=\"vncellreq\">";
+ $form .= "<table id='maintable'>";
+ $form .= "<tbody><tr>";
+ $form .= "<td width='35%'><div id='onecolumn'>Bandwidth</div></td>";
+ //$form .= "<td width='35%'><div id='fifthcolumn'>Burst</div></td>";
+ $form .= "<td width='20%'><div id='twocolumn'>Bw type</div></td>";
+ $form .= "<td width='35%' ><div id='thirdcolumn'>Schedule</div></td>";
+ $form .= "<td width='5%'><div id='fourthcolumn'></div></td>";
+ $form .= "</tr>";
+ if (is_array($bandwidth)) {
+ foreach ($bandwidth as $bwidx => $bw) {
+ $form .= "\n<tr><td width='40%'>";
+ $form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
+ //$form .= "</td><td width='20%'>";
+ //$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"burst{$bwidx}\" name=\"burst{$bwidx}\" value=\"{$bw['burst']}\" />";
+ $form .= "</td><td width='20%'>";
+ $form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"formselect\">";
+ foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
+ $form .= "<option value=\"{$bwsidx}\"";
+ if ($bw['bwscale'] == $bwsidx) {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">{$bwscale}</option>";
+ }
+ $form .= "</select>";
+ $form .= "</td><td width='35%' >";
+ $form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"formselect\">";
+ foreach ($schedules as $schd) {
+ $selected = "";
+ if ($bw['bwsched'] == $schd) {
+ $selected = "selected=\"selected\"";
+ }
+ $form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
+ }
+ $form .= "</select>";
+ $form .= "</td><td width='5%' >";
+ $form .= "<a onclick=\"removeBwRow(this); return false;\" href='#'><img border='0' src='/themes/{$g['theme']}/images/icons/icon_x.gif' alt='remove' /></a>";
+ $form .= "</td></tr>";
+ }
+ }
+ $form .= "</tbody></table>";
+ $form .= "<a onclick=\"javascript:addBwRowTo('maintable'); return false;\" href='#'>";
+ $form .= "<img border='0' src='/themes/{$g['theme']}/images/icons/icon_plus.gif' alt='add' title='" . gettext("add another schedule") . "' /></a>";
+ //$form .= "<br /><span class=\"vexpl\">" . gettext("Bandwidth is a rate (e.g. Mbit/s), burst is a total amount of data that will be transferred at full speed after an idle period.") . "</span><br />";
+ $form .= "<br /><span class=\"vexpl\">" . gettext("Bandwidth is the rate (e.g. Mbit/s) to which traffic in this limiter will be restricted.") . "</span><br />";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
+ $form .= "<option value=\"none\"";
+ $mask = $this->GetMask();
+ if ($mask['type'] == "none") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">none</option>";
+ $form .= "<option value=\"srcaddress\"";
+ if ($mask['type'] == "srcaddress") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Source addresses") . "</option>";
+ $form .= "<option value=\"dstaddress\"";
+ if ($mask['type'] == "dstaddress") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Destination addresses") . "</option>";
+ $form .= "</select>";
+ $form .= "&nbsp;<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
+ . "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
+ . "be created for each source/destination IP address encountered, \n"
+ . "respectively. This makes it possible to easily specify bandwidth \n"
+ . "limits per host.") . "</span><br />";
+ $form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
+ if ($mask['type'] <> "none") {
+ $form .= $mask['bits'];
+ }
+ $form .= "\"";
+ if ($mask['type'] == "none") {
+ $form .= " disabled";
+ }
+ $form .= " />";
+ $form .= "&nbsp; IPV4 mask bits (1-32)<br />";
+ $form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
+ if ($mask['type'] <> "none") {
+ $form .= $mask['bitsv6'];
+ }
+ $form .= "\"";
+ if ($mask['type'] == "none") {
+ $form .= " disabled";
+ }
+ $form .= " />";
+ $form .= "&nbsp; IPV6 mask bits (1-128)<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
+ . "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
+ . "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
+ . "per pipe.") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
+ $form .= htmlspecialchars($this->GetDescription());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">";
+ $form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr id=\"sprtable4\">";
+ $form .= "<td></td>";
+ $form .= "<td><div id=\"showadvancedboxspr\">";
+ $form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
+ $form .= " value=\"" . gettext("Show advanced options") . "\" />";
+ $form .= "</p></div></td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable\">";
+
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Delay") . "</td>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">";
+ $form .= "<input name=\"delay\" type=\"text\" id=\"delay\" size=\"5\" value=\"";
+ $form .= $this->GetDelay() . "\" />";
+ $form .= "&nbsp;ms<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should specify 0 here (or leave the field empty)") . "</span><br />";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable1\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">";
+ $form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
+ $form .= $this->GetPlr() . "\" />";
+ $form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should specify 0 here (or leave the field empty). "
+ . "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable2\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
+ $form .= $this->GetQlimit() . "\" />";
+ $form .= "&nbsp;slots<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
+ . "then they are delayed by value specified in the Delay field, and then they "
+ . "are delivered to their destination.") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable5\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
+ $form .= $this->GetBuckets() . "\" />";
+ $form .= "&nbsp;slots<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should leave the field empty. It increases the hash size set.");
+ $form .= "</span></td></tr>";
+
+ return $form;
+
+ }
+
+ function wconfig() {
+ $cflink =& get_dn_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['number'] = $this->GetNumber();
+ $cflink['qlimit'] = $this->GetQlimit();
+ $cflink['plr'] = $this->GetPlr();
+ $cflink['description'] = $this->GetDescription();
+
+ $bandwidth = $this->GetBandwidth();
+ if (is_array($bandwidth)) {
+ $cflink['bandwidth'] = array();
+ $cflink['bandwidth']['item'] = array();
+ foreach ($bandwidth as $bwidx => $bw) {
+ $cflink['bandwidth']['item'][] = $bw;
+ }
+ }
+
+ $cflink['enabled'] = $this->GetEnabled();
+ $cflink['buckets'] = $this->GetBuckets();
+ $mask = $this->GetMask();
+ $cflink['mask'] = $mask['type'];
+ $cflink['maskbits'] = $mask['bits'];
+ $cflink['maskbitsv6'] = $mask['bitsv6'];
+ $cflink['delay'] = $this->GetDelay();
+ }
+
+}
+
+class dnqueue_class extends dummynet_class {
+ var $pipeparent;
+ var $weight;
+
+ function GetWeight() {
+ return $this->weight;
+ }
+ function SetWeight($weight) {
+ $this->weight = $weight;
+ }
+ function GetPipe() {
+ return $this->pipeparent;
+ }
+ function SetPipe($pipe) {
+ $this->pipeparent = $pipe;
+ }
+
+ /* Just a stub in case we ever try to call this from the frontend. */
+ function &add_queue($interface, &$queue, &$path, &$input_errors) {
+ return;
+ }
+
+ function delete_queue() {
+ cleanup_dnqueue_from_rules($this->GetQname());
+ unset_dn_object_by_reference($this->GetLink());
+ @pfSense_pipe_action("queue delete " . $this->GetNumber());
+ }
+
+ function validate_input($data, &$input_errors) {
+ parent::validate_input($data, $input_errors);
+
+ if ($data['weight'] && ((!is_numeric($data['weight'])) ||
+ ($data['weight'] < 1 && $data['weight'] > 100))) {
+ $input_errors[] = gettext("Weight must be an integer between 1 and 100.");
+ }
+ }
+
+ /*
+ * Should search even its children
+ */
+ function &find_queue($pipe, $qname) {
+ if ($qname == $this->GetQname()) {
+ return $this;
+ } else {
+ return NULL;
+ }
+ }
+
+ function &find_parentqueue($pipe, $qname) {
+ return $this->qparent;
+ }
+
+ function &get_queue_list(&$qlist) {
+ if ($this->GetEnabled() == "") {
+ return;
+ }
+ $qlist[$this->GetQname()] = "?" .$this->GetNumber();
+ }
+
+ function ReadConfig(&$q) {
+ if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
+ $this->SetQname($q['newname']);
+ } else if (!empty($q['newname'])) {
+ $this->SetQname($q['newname']);
+ } else {
+ $this->SetQname($q['name']);
+ }
+ $this->SetNumber($q['number']);
+ if (isset($q['qlimit']) && $q['qlimit'] <> "") {
+ $this->SetQlimit($q['qlimit']);
+ } else {
+ $this->SetQlimit("");
+ }
+ if (isset($q['mask']) && $q['mask'] <> "") {
+ $masktype = $q['mask'];
+ } else {
+ $masktype = "";
+ }
+ if (isset($q['maskbits']) && $q['maskbits'] <> "") {
+ $maskbits = $q['maskbits'];
+ } else {
+ $maskbits = "";
+ }
+ if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
+ $maskbitsv6 = $q['maskbitsv6'];
+ } else {
+ $maskbitsv6 = "";
+ }
+ $this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
+ if (isset($q['buckets']) && $q['buckets'] <> "") {
+ $this->SetBuckets($q['buckets']);
+ } else {
+ $this->SetBuckets("");
+ }
+ if (isset($q['plr']) && $q['plr'] <> "") {
+ $this->SetPlr($q['plr']);
+ } else {
+ $this->SetPlr("");
+ }
+ if (isset($q['weight']) && $q['weight'] <> "") {
+ $this->SetWeight($q['weight']);
+ } else {
+ $this->SetWeight("");
+ }
+ if (isset($q['description']) && $q['description'] <> "") {
+ $this->SetDescription($q['description']);
+ } else {
+ $this->SetDescription("");
+ }
+ $this->SetEnabled($q['enabled']);
+ }
+
+ function build_tree() {
+ $parent =& $this->GetParent();
+ $tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
+ $tree .= $this->GetQname() . "</a>";
+ $tree .= "</li>";
+
+ return $tree;
+ }
+
+ function build_rules() {
+ if ($this->GetEnabled() == "") {
+ return;
+ }
+
+ $parent =& $this->GetParent();
+ $pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
+ if ($this->GetQlimit()) {
+ $pfq_rule .= " queue " . $this->GetQlimit();
+ }
+ if ($this->GetWeight()) {
+ $pfq_rule .= " weight " . $this->GetWeight();
+ }
+ if ($this->GetBuckets()) {
+ $pfq_rule .= " buckets " . $this->GetBuckets();
+ }
+ $this->build_mask_rules($pfq_rule);
+ $pfq_rule .= "\n";
+
+ return $pfq_rule;
+ }
+
+ function build_javascript() {
+ return parent::build_javascript();
+ }
+
+
+ function build_form() {
+ $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
+ $form .= gettext("Enable/Disable");
+ $form .= "</td><td class=\"vncellreq\">";
+ $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
+ if ($this->GetEnabled() == "on") {
+ $form .= " checked=\"checked\"";
+ }
+ $form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
+ $form .= $this->GetQname()."\" />";
+ $form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
+ $form .= $this->GetQname()."\" />";
+ if ($this->GetNumber() > 0) {
+ $form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
+ $form .= $this->GetNumber()."\" />";
+ }
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
+ $form .= "<option value=\"none\"";
+ $mask = $this->GetMask();
+ if ($mask['type'] == "none") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("none") . "</option>";
+ $form .= "<option value=\"srcaddress\"";
+ if ($mask['type'] == "srcaddress") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Source addresses") . "</option>";
+ $form .= "<option value=\"dstaddress\"";
+ if ($mask['type'] == "dstaddress") {
+ $form .= " selected=\"selected\"";
+ }
+ $form .= ">" . gettext("Destination addresses") . "</option>";
+ $form .= "</select>";
+ $form .= "&nbsp;slots<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
+ . "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
+ . "be created for each source/destination IP address encountered, \n"
+ . "respectively. This makes it possible to easily specify bandwidth \n"
+ . "limits per host.") . "</span><br />";
+ $form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
+ if ($mask['type'] <> "none") {
+ $form .= $mask['bits'];
+ }
+ $form .= "\"";
+ if ($mask['type'] == "none") {
+ $form .= " disabled";
+ }
+ $form .= " />";
+ $form .= "&nbsp; IPV4 mask bits (1-32)<br />";
+ $form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
+ if ($mask['type'] <> "none") {
+ $form .= $mask['bitsv6'];
+ }
+ $form .= "\"";
+ if ($mask['type'] == "none") {
+ $form .= " disabled";
+ }
+ $form .= " />";
+ $form .= "&nbsp; IPV6 mask bits (1-128)<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
+ . "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
+ . "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
+ . "per queue.") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"description\" class=\"formfld unknown\" size=\"40\" name=\"description\" value=\"";
+ $form .= htmlspecialchars($this->GetDescription());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">";
+ $form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr id=\"sprtable4\">";
+ $form .= "<td></td>";
+ $form .= "<td><div id=\"showadvancedboxspr\">";
+ $form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
+ $form .= " value=\"" . gettext("Show advanced options") . "\" />";
+ $form .= "</p></div></td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Weight") . "</td>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">";
+ $form .= "<input name=\"weight\" type=\"text\" id=\"weight\" size=\"5\" value=\"";
+ $form .= $this->GetWeight() . "\" />";
+ $form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: For queues under the same parent "
+ . "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable1\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">";
+ $form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
+ $form .= $this->GetPlr() . "\" />";
+ $form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should specify 0 here (or leave the field empty). "
+ . "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable2\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
+ $form .= $this->GetQlimit() . "\" />";
+ $form .= "&nbsp;slots<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
+ . "then they are delayed by value specified in the Delay field, and then they "
+ . "are delivered to their destination.") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr style=\"display:none\" id=\"sprtable5\">";
+ $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
+ $form .= $this->GetBuckets() . "\" />";
+ $form .= "&nbsp;" . gettext("slots") . "<br />";
+ $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
+ . "should leave the field empty. It increases the hash size set.");
+ $form .= "</span></td></tr>";
+
+ $form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
+ $form .= " value=\"" . $this->GetPipe() . "\" />";
+
+ return $form;
+
+ }
+
+ function update_dn_data(&$data) {
+ $this->ReadConfig($data);
+ }
+
+ function wconfig() {
+ $cflink =& get_dn_reference_to_me_in_config($this->GetLink());
+ if (!is_array($cflink)) {
+ $cflink = array();
+ }
+ $cflink['name'] = $this->GetQname();
+ $cflink['number'] = $this->GetNumber();
+ $cflink['qlimit'] = $this->GetQlimit();
+ $cflink['description'] = $this->GetDescription();
+ $cflink['weight'] = $this->GetWeight();
+ $cflink['enabled'] = $this->GetEnabled();
+ $cflink['buckets'] = $this->GetBuckets();
+ $mask = $this->GetMask();
+ $cflink['mask'] = $mask['type'];
+ $cflink['maskbits'] = $mask['bits'];
+ $cflink['maskbitsv6'] = $mask['bitsv6'];
+ }
+}
+
+// List of layer7 objects
+$layer7_rules_list = array();
+
+class layer7 {
+
+ var $rname; //alias
+ var $rdescription; //alias description
+ var $rport; //divert port
+ var $renabled; //rule enabled
+ var $rsets = array(); //array of l7 associations
+
+ // Auxiliary functions
+
+ function GetRName() {
+ return $this->rname;
+ }
+ function SetRName($rname) {
+ $this->rname = $rname;
+ }
+ function GetRDescription() {
+ return $this->rdescription;
+ }
+ function SetRDescription($rdescription) {
+ $this->rdescription = $rdescription;
+ }
+ function GetRPort() {
+ return $this->rport;
+ }
+ function SetRPort($rport) {
+ $this->rport = $rport;
+ }
+ function GetREnabled() {
+ return $this->renabled;
+ }
+ function SetREnabled($value) {
+ $this->renabled = $value;
+ }
+ function GetRl7() {
+ return $this->rsets;
+ }
+ function SetRl7($rsets) {
+ $this->rsets = $rsets;
+ }
+
+ //Add a tuple (rule,structure,element) to the $rsets
+
+ function add_rule($l7set) {
+ $this->rsets[] = $l7set;
+ }
+
+ // Build the layer7 rules
+ function build_l7_rules() {
+ if ($this->GetREnabled() == "") {
+ return;
+ }
+ //$l7rules = "#" . $this->rdescription . "\n";
+ foreach ($this->rsets as $rl7) {
+ $l7rules .= $rl7->build_rules();
+ }
+ return $l7rules;
+ }
+
+ // Read the config from array
+ function ReadConfig(&$qname, &$q) {
+ $this->SetRName($qname);
+ $this->SetREnabled($q['enabled']);
+ $this->SetRPort($q['divert_port']);
+ if (isset($q['description']) && $q['description'] <> "") {
+ $this->SetRDescription($q['description']);
+ }
+ $rsets = $q['l7rules'];
+ //Put individual rules in the array
+ if (is_array($rsets)) {
+ $this->rsets = array(); // XXX: ugly hack
+ foreach ($rsets as $l7r) {
+ $l7obj = new l7rule();
+ $l7obj->SetRProtocol($l7r['protocol']);
+ $l7obj->SetRStructure($l7r['structure']);
+ $l7obj->SetRBehaviour($l7r['behaviour']);
+ $this->add_rule($l7obj);
+ }
+ }
+ }
+
+ //Generate a random port for the divert socket
+ function gen_divert_port() {
+ $dports = get_divert_ports(); //array of used ports
+ $divert_port = 1; // Initialize
+ while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
+ $divert_port = rand(40000, 60000);
+ }
+ return $divert_port;
+ }
+
+ //Helps building the left tree
+ function build_tree() {
+ $tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">";
+ $tree .= $this->GetRName() . "</a>";
+ $tree .= "</li>";
+
+ return $tree;
+ }
+
+ function build_form() {
+ $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
+ $form .= gettext("Enable/Disable");
+ $form .= "</td><td class=\"vncellreq\">";
+ $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
+ if ($this->GetREnabled() == "on") {
+ $form .= "checked=\"checked\"";
+ }
+ $form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
+ $form .= $this->GetRName()."\" />";
+ $form .= "</td></tr>";
+ $form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
+ $form .= "<td class=\"vncellreq\">";
+ $form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
+ $form .= htmlspecialchars($this->GetRDescription());
+ $form .= "\" />";
+ $form .= "<br /> <span class=\"vexpl\">";
+ $form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
+ $form .= "</td></tr>";
+
+ return $form;
+ }
+
+ //Write the setting to the $config array
+ function wconfig() {
+ global $config;
+
+ if (!is_array($config['l7shaper']['container'])) {
+ $config['l7shaper']['container'] = array();
+ }
+ //
+ $cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
+ // Test if this rule exists already
+ if (!$cflink) {
+ $cflink =& $config['l7shaper']['container'][];
+ }
+ $cflink['name'] = $this->GetRName();
+ $cflink['enabled'] = $this->GetREnabled();
+ $cflink['description'] = $this->GetRDescription();
+ $cflink['divert_port'] = $this->GetRPort();
+
+ // Destroy previously existent rules
+ if (is_array($cflink['rules'])) {
+ unset($cflink['l7rules']);
+ }
+
+ $cflink['l7rules'] = array();
+
+ $i = 0;
+ foreach ($this->rsets as $rulel7) {
+ $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
+ $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
+ $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
+ $i++;
+ }
+ }
+
+ //This function is necessary to help producing the overload options for keep state
+ function get_unique_structures() {
+
+ $unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
+ foreach ($this->rsets as $l7rule) {
+ if ($l7rule->GetRStructure() == "action") {
+ $unique_structures['action'] = true;
+ } else if ($l7rule->GetRStructure() == "limiter") {
+ $unique_structures['dummynet'] = true;
+ } else {
+ $unique_structures['altq'] = true;
+ }
+ }
+ //Delete non used structures so we don't have to check this in filter.inc
+ foreach ($unique_structures as $key => $value) {
+ if (!$value) {
+ unset($unique_structures[$key]);
+ }
+ }
+ return $unique_structures;
+ }
+
+ function validate_input($data, &$input_errors) {
+ $reqdfields[] = "container";
+ $reqdfieldsn[] = gettext("Name");
+
+ shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
+
+ if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container'])) {
+ $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
+ }
+ }
+
+ function delete_l7c() {
+ mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
+ unset_l7_object_by_reference($this->GetRName());
+ cleanup_l7_from_rules($this->GetRName());
+ }
+}
+
+class l7rule {
+
+ var $rprotocol; //protocol
+ var $rstructure; //action, limiter, queue
+ var $rbehaviour; //allow, block, queue_name, pipe_number ...
+
+ //Auxiliary Functions
+
+ function GetRProtocol() {
+ return $this->rprotocol;
+ }
+ function SetRProtocol($rprotocol) {
+ $this->rprotocol = $rprotocol;
+ }
+ function GetRStructure() {
+ return $this->rstructure;
+ }
+ function SetRStructure($rstructure) {
+ $this->rstructure = $rstructure;
+ }
+ function GetRBehaviour() {
+ return $this->rbehaviour;
+ }
+ function SetRBehaviour($rbehaviour) {
+ $this->rbehaviour = $rbehaviour;
+ }
+
+ //XXX Do we need to test any particularity for AltQ queues?
+ function build_rules() {
+ global $dummynet_pipe_list;
+ switch ($this->GetRStructure()) {
+ case "limiter":
+ read_dummynet_config();
+ $dn_list =& get_unique_dnqueue_list();
+ $found = false;
+ if (is_array($dn_list)) {
+ foreach ($dn_list as $key => $value) {
+ if ($key == $this->GetRBehaviour()) {
+ if ($value[0] == "?") {
+ $l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
+ } else {
+ $l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
+ }
+ $found = true;
+ }
+ if ($found) {
+ break;
+ }
+ }
+ }
+ break;
+ default: //This is for action and for altq
+ $l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
+ break;
+ }
+ return $l7rule;
+ }
+}
+
+/*
+ * This function allows to return an array with all the used divert socket ports
+ */
+function get_divert_ports() {
+ global $layer7_rules_list;
+ $dports = array();
+
+ foreach ($layer7_rules_list as $l7r) {
+ $dports[] = $l7r->GetRPort();
+ }
+
+ return $dports;
+}
+
+function &get_l7c_reference_to_me_in_config(&$name) {
+ global $config;
+
+ $ptr = NULL;
+
+ if (is_array($config['l7shaper']['container'])) {
+ foreach ($config['l7shaper']['container'] as $key => $value) {
+ if ($value['name'] == $name) {
+ $ptr =& $config['l7shaper']['container'][$key];
+ }
+ }
+ }
+ return $ptr;
+ // $ptr can be null. has to be checked later
+}
+
+function unset_l7_object_by_reference(&$name) {
+ global $config;
+
+ if (is_array($config['l7shaper']['container'])) {
+ foreach ($config['l7shaper']['container'] as $key => $value) {
+ if ($value['name'] == $name) {
+ unset($config['l7shaper']['container'][$key]['l7rules']);
+ unset($config['l7shaper']['container'][$key]);
+ break;
+ }
+ }
+ }
+}
+
+function read_layer7_config() {
+ global $layer7_rules_list, $config;
+
+ if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) {
+ $layer7_rules_list = array();
+ return;
+ }
+
+ $l7cs = &$config['l7shaper']['container'];
+
+ $layer7_rules_list = array();
+
+ foreach ($l7cs as $conf) {
+ if (empty($conf['name'])) {
+ continue; /* XXX: grrrrrr at php */
+ }
+ $root =& new layer7();
+ $root->ReadConfig($conf['name'], $conf);
+ $layer7_rules_list[$root->GetRName()] = &$root;
+ }
+}
+
+function update_layer7_custom_patterns() {
+ global $config;
+
+ if (!is_array($config['l7shaper']['custom_pat'])) {
+ return;
+ }
+
+ foreach ($config['l7shaper']['custom_pat'] as $filename => $filecontent) {
+ if (!file_exists("/usr/local/share/protocols/" . $filename)) {
+ @file_put_contents("/usr/local/share/protocols/" . $filename, base64_decode($filecontent));
+ }
+ }
+}
+
+function generate_layer7_files() {
+ global $layer7_rules_list, $g;
+
+ read_layer7_config();
+
+ if (!empty($layer7_rules_list)) {
+ if (!is_module_loaded("ipdivert.ko")) {
+ mwexec("/sbin/kldload ipdivert.ko");
+ }
+
+ array_map('unlink', glob("{$g['tmp_path']}/*.l7"));
+ }
+
+ update_layer7_custom_patterns();
+
+ foreach ($layer7_rules_list as $l7rules) {
+ if ($l7rules->GetREnabled()) {
+ $filename = $l7rules->GetRName() . ".l7";
+ $path = "{$g['tmp_path']}/" . $filename;
+
+ $rules = $l7rules->build_l7_rules();
+
+ $fp = fopen($path, 'w');
+ fwrite($fp, $rules);
+ fclose($fp);
+ }
+ }
+}
+
+function layer7_start_l7daemon() {
+ global $layer7_rules_list, $g;
+
+ /*
+ * XXX: ermal - Needed ?!
+ * read_layer7_config();
+ */
+
+ foreach ($layer7_rules_list as $l7rules) {
+ if ($l7rules->GetREnabled()) {
+ $filename = $l7rules->GetRName() . ".l7";
+ $path = "{$g['tmp_path']}/" . $filename;
+
+ unset($l7pid);
+ /* Only reread the configuration rather than restart to avoid losing information. */
+ exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
+ if (count($l7pid) > 0) {
+ log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
+ mwexec("/bin/kill -HUP {$l7pid[0]}");
+ } else {
+ // XXX: Hardcoded number of packets to garbage collect and queue length.
+ $ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
+ mwexec_bg($ipfw_classifyd_init);
+ }
+ }
+ }
+}
+
+// This function uses /usr/local/share/protocols as a default directory for searching .pat files
+function generate_protocols_array() {
+
+ update_layer7_custom_patterns();
+
+ $protocols = return_dir_as_array("/usr/local/share/protocols");
+ $protocols_new = array();
+ if (is_array($protocols)) {
+ foreach ($protocols as $key => $proto) {
+ if (strstr($proto, ".pat")) {
+ $protocols_new[$key] =& str_replace(".pat", "", $proto);
+ }
+ }
+ sort($protocols_new);
+ }
+ return $protocols_new;
+}
+
+function get_l7_unique_list() {
+ global $layer7_rules_list;
+
+ $l7list = array();
+ if (is_array($layer7_rules_list)) {
+ foreach ($layer7_rules_list as $l7c) {
+ if ($l7c->GetREnabled()) {
+ $l7list[] = $l7c->GetRName();
+ }
+ }
+ }
+
+ return $l7list;
+}
+
+// Disable a removed l7 container from the filter
+function cleanup_l7_from_rules(&$name) {
+ global $config;
+
+ if (is_array($config['filter']['rule'])) {
+ foreach ($config['filter']['rule'] as $key => $rule) {
+ if ($rule['l7container'] == $name) {
+ unset($config['filter']['rule'][$key]['l7container']);
+ }
+ }
+ }
+}
+
+function get_dummynet_name_list() {
+
+ $dn_name_list =& get_unique_dnqueue_list();
+ $dn_name = array();
+ if (is_array($dn_name_list)) {
+ foreach ($dn_name_list as $key => $value) {
+ $dn_name[] = $key;
+ }
+ }
+
+ return $dn_name;
+
+}
+
+function get_altq_name_list() {
+ $altq_name_list =& get_unique_queue_list();
+ $altq_name = array();
+ if (is_array($altq_name_list)) {
+ foreach ($altq_name_list as $key => $aqobj) {
+ $altq_name[] = $key;
+ }
+ }
+
+ return $altq_name;
+}
+
+/*
+ * XXX: TODO Make a class shaper to hide all these functions
+ * from the global namespace.
+ */
+
+/*
+ * This is a layer violation but for now there is no way
+ * I can find to properly do this with PHP.
+ */
+function altq_get_default_queue($interface) {
+ global $altq_list_queues;
+
+ $altq_tmp = $altq_list_queues[$interface];
+ if ($altq_tmp) {
+ return $altq_tmp->GetDefaultQueuePresent();
+ } else {
+ return false;
+ }
+}
+
+function altq_check_default_queues() {
+ global $altq_list_queues;
+
+ $count = 0;
+ if (is_array($altq_list_queues)) {
+ foreach ($altq_list_queues as $altq) {
+ if ($altq->GetDefaultQueuePresent()) {
+ $count++;
+ }
+ }
+ }
+ else {
+ $count++;
+ }
+
+ return 0;
+}
+
+function &get_unique_queue_list() {
+ global $altq_list_queues;
+
+ $qlist = array();
+ if (is_array($altq_list_queues)) {
+ foreach ($altq_list_queues as $altq) {
+ if ($altq->GetEnabled() == "") {
+ continue;
+ }
+ $tmplist =& $altq->get_queue_list();
+ foreach ($tmplist as $qname => $link) {
+ if ($link->GetEnabled() <> "") {
+ $qlist[$qname] = $link;
+ }
+ }
+ }
+ }
+ return $qlist;
+}
+
+function &get_unique_dnqueue_list() {
+ global $dummynet_pipe_list;
+
+ $qlist = array();
+ if (is_array($dummynet_pipe_list)) {
+ foreach ($dummynet_pipe_list as $dn) {
+ if ($dn->GetEnabled() == "") {
+ continue;
+ }
+ $tmplist =& $dn->get_queue_list();
+ foreach ($tmplist as $qname => $link) {
+ $qlist[$qname] = $link;
+ }
+ }
+ }
+ return $qlist;
+}
+
+function ref_on_altq_queue_list($parent, $qname) {
+ if (isset($GLOBALS['queue_list'][$qname])) {
+ $GLOBALS['queue_list'][$qname]++;
+ } else {
+ $GLOBALS['queue_list'][$qname] = 1;
+ }
+
+ unref_on_altq_queue_list($parent);
+}
+
+function unref_on_altq_queue_list($qname) {
+ $GLOBALS['queue_list'][$qname]--;
+ if ($GLOBALS['queue_list'][$qname] <= 1) {
+ unset($GLOBALS['queue_list'][$qname]);
+ }
+}
+
+function read_altq_config() {
+ global $altq_list_queues, $config;
+ $path = array();
+
+ if (!is_array($config['shaper'])) {
+ $config['shaper'] = array();
+ }
+ if (!is_array($config['shaper']['queue'])) {
+ $config['shaper']['queue'] = array();
+ }
+ $a_int = &$config['shaper']['queue'];
+
+ $altq_list_queues = array();
+
+ if (!is_array($config['shaper']['queue'])) {
+ return;
+ }
+
+ foreach ($a_int as $key => $conf) {
+ $int = $conf['interface'];
+ $root =& new altq_root_queue();
+ $root->SetInterface($int);
+ $altq_list_queues[$root->GetInterface()] = &$root;
+ $root->ReadConfig($conf);
+ array_push($path, $key);
+ $root->SetLink($path);
+ if (is_array($conf['queue'])) {
+ foreach ($conf['queue'] as $key1 => $q) {
+ array_push($path, $key1);
+ /*
+ * XXX: we completely ignore errors here but anyway we must have
+ * checked them before so no harm should be come from this.
+ */
+ $root->add_queue($root->GetInterface(), $q, $path, $input_errors);
+ array_pop($path);
+ }
+ }
+ array_pop($path);
+ }
+}
+
+function read_dummynet_config() {
+ global $dummynet_pipe_list, $config;
+ $path = array();
+
+ if (!is_array($config['dnshaper'])) {
+ $config['dnshaper'] = array();
+ }
+ if (!is_array($config['dnshaper']['queue'])) {
+ $config['dnshaper']['queue'] = array();
+ }
+ $a_int = &$config['dnshaper']['queue'];
+
+ $dummynet_pipe_list = array();
+
+ if (!is_array($config['dnshaper']['queue']) ||
+ !count($config['dnshaper']['queue'])) {
+ return;
+ }
+
+ foreach ($a_int as $key => $conf) {
+ if (empty($conf['name'])) {
+ continue; /* XXX: grrrrrr at php */
+ }
+ $root =& new dnpipe_class();
+ $root->ReadConfig($conf);
+ $dummynet_pipe_list[$root->GetQname()] = &$root;
+ array_push($path, $key);
+ $root->SetLink($path);
+ if (is_array($conf['queue'])) {
+ foreach ($conf['queue'] as $key1 => $q) {
+ array_push($path, $key1);
+ /*
+ * XXX: we completely ignore errors here but anyway we must have
+ * checked them before so no harm should be come from this.
+ */
+ $root->add_queue($root->GetQname(), $q, $path, $input_errors);
+ array_pop($path);
+ }
+ }
+ array_pop($path);
+ }
+}
+
+function get_interface_list_to_show() {
+ global $altq_list_queues, $config;
+ global $shaperIFlist;
+
+ $tree = "";
+ foreach ($shaperIFlist as $shif => $shDescr) {
+ if ($altq_list_queues[$shif]) {
+ continue;
+ } else {
+ if (!is_altq_capable(get_real_interface($shif))) {
+ continue;
+ }
+ $tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
+ }
+ }
+
+ return $tree;
+}
+
+function filter_generate_altq_queues() {
+ global $altq_list_queues;
+
+ read_altq_config();
+
+ $altq_rules = "";
+ foreach ($altq_list_queues as $altq) {
+ $altq_rules .= $altq->build_rules();
+ }
+
+ return $altq_rules;
+}
+
+function dnqueue_find_nextnumber() {
+ global $dummynet_pipe_list;
+
+ $dnused = array();
+ if (is_array($dummynet_pipe_list)) {
+ foreach ($dummynet_pipe_list as $dn) {
+ $tmplist =& $dn->get_queue_list();
+ foreach ($tmplist as $qname => $link) {
+ if ($link[0] == "?") {
+ $dnused[$qname] = substr($link, 1);
+ }
+ }
+ }
+ }
+
+ sort($dnused, SORT_NUMERIC);
+ $dnnumber = 0;
+ $found = false;
+ foreach ($dnused as $dnnum) {
+ if (($dnnum - $dnnumber) > 1) {
+ $dnnumber = $dnnum - 1;
+ $found = true;
+ break;
+ } else {
+ $dnnumber = $dnnum;
+ }
+ }
+
+ if ($found == false) {
+ $dnnumber++;
+ }
+
+ unset($dnused, $dnnum, $found);
+ return $dnnumber;
+}
+
+function dnpipe_find_nextnumber() {
+ global $dummynet_pipe_list;
+
+ $dnused = array();
+ foreach ($dummynet_pipe_list as $dn) {
+ $dnused[] = $dn->GetNumber();
+ }
+
+ sort($dnused, SORT_NUMERIC);
+ $dnnumber = 0;
+ $found = false;
+ foreach ($dnused as $dnnum) {
+ if (($dnnum - $dnnumber) > 1) {
+ $dnnumber = $dnnum - 1;
+ $found = true;
+ break;
+ } else {
+ $dnnumber = $dnnum;
+ }
+ }
+
+ if ($found == false) {
+ $dnnumber++;
+ }
+
+ unset($dnused, $dnnum, $found);
+ return $dnnumber;
+}
+
+function filter_generate_dummynet_rules() {
+ global $g, $dummynet_pipe_list;
+
+ read_dummynet_config();
+
+ $dn_rules = "";
+ foreach ($dummynet_pipe_list as $dn) {
+ $dn_rules .= $dn->build_rules();
+ }
+
+ if (!empty($dn_rules)) {
+ if (!is_module_loaded("dummynet.ko")) {
+ mwexec("/sbin/kldload dummynet");
+ set_sysctl(array(
+ "net.inet.ip.dummynet.io_fast" => "1",
+ "net.inet.ip.dummynet.hash_size" => "256"
+ ));
+ }
+ file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
+ mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
+ }
+}
+
+function build_iface_without_this_queue($iface, $qname) {
+ global $g, $altq_list_queues;
+ global $shaperIFlist;
+
+ $altq =& $altq_list_queues[$iface];
+ if ($altq) {
+ $scheduler = ": " . $altq->GetScheduler();
+ }
+ $form = "<tr><td width=\"20%\" >";
+ $form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
+ $form .= "</td></tr>";
+ $form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
+ $form .= "<a href=\"firewall_shaper_queues.php?interface=";
+ $form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
+ $form .= "<img src=\"";
+ $form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
+ $form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
+ $form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
+
+ return $form;
+
+}
+
+
+$default_shaper_msg = "<tr><td align=\"center\" width=\"80%\">";
+$default_shaper_msg .= "<span class=\"vexpl\"><strong><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
+$default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
+ . "buttons at the bottom represent queue actions and are activated accordingly.");
+$default_shaper_msg .= "</strong></span>";
+$default_shaper_msg .= "</td></tr>";
+
+$dn_default_shaper_msg = "<tr><td align=\"center\" width=\"80%\">";
+$dn_default_shaper_msg .= "<span class=\"vexpl\"><strong><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
+$dn_default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
+ . "buttons at the bottom represent queue actions and are activated accordingly.");
+$dn_default_shaper_msg .= "</strong></span>";
+$dn_default_shaper_msg .= "</td></tr>";
+
+?>
diff --git a/src/etc/inc/simplepie/LICENSE.txt b/src/etc/inc/simplepie/LICENSE.txt
new file mode 100644
index 0000000..a822a4b
--- /dev/null
+++ b/src/etc/inc/simplepie/LICENSE.txt
@@ -0,0 +1,26 @@
+Copyright (c) 2004-2007, Ryan Parman and Geoffrey Sneddon.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ to endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/src/etc/inc/simplepie/simplepie.inc b/src/etc/inc/simplepie/simplepie.inc
new file mode 100644
index 0000000..7052eb4
--- /dev/null
+++ b/src/etc/inc/simplepie/simplepie.inc
@@ -0,0 +1,13672 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2008, Ryan Parman and Geoffrey Sneddon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.1.3
+ * @copyright 2004-2008 Ryan Parman, Geoffrey Sneddon
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @link http://simplepie.org/ SimplePie
+ * @link http://simplepie.org/support/ Please submit all bug reports and feature requests to the SimplePie forums
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @todo phpDoc comments
+ */
+
+/**
+ * SimplePie Name
+ */
+define('SIMPLEPIE_NAME', 'SimplePie');
+
+/**
+ * SimplePie Version
+ */
+define('SIMPLEPIE_VERSION', '1.1.3');
+
+/**
+ * SimplePie Build
+ */
+define('SIMPLEPIE_BUILD', 20081219);
+
+/**
+ * SimplePie Website URL
+ */
+define('SIMPLEPIE_URL', 'http://simplepie.org');
+
+/**
+ * SimplePie Useragent
+ * @see SimplePie::set_useragent()
+ */
+define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
+
+/**
+ * SimplePie Linkback
+ */
+define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
+
+/**
+ * No Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_NONE', 0);
+
+/**
+ * Feed Link Element Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
+
+/**
+ * Local Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
+
+/**
+ * Local Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
+
+/**
+ * Remote Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
+
+/**
+ * Remote Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
+
+/**
+ * All Feed Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_ALL', 31);
+
+/**
+ * No known feed type
+ */
+define('SIMPLEPIE_TYPE_NONE', 0);
+
+/**
+ * RSS 0.90
+ */
+define('SIMPLEPIE_TYPE_RSS_090', 1);
+
+/**
+ * RSS 0.91 (Netscape)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
+
+/**
+ * RSS 0.91 (Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
+
+/**
+ * RSS 0.91 (both Netscape and Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091', 6);
+
+/**
+ * RSS 0.92
+ */
+define('SIMPLEPIE_TYPE_RSS_092', 8);
+
+/**
+ * RSS 0.93
+ */
+define('SIMPLEPIE_TYPE_RSS_093', 16);
+
+/**
+ * RSS 0.94
+ */
+define('SIMPLEPIE_TYPE_RSS_094', 32);
+
+/**
+ * RSS 1.0
+ */
+define('SIMPLEPIE_TYPE_RSS_10', 64);
+
+/**
+ * RSS 2.0
+ */
+define('SIMPLEPIE_TYPE_RSS_20', 128);
+
+/**
+ * RDF-based RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_RDF', 65);
+
+/**
+ * Non-RDF-based RSS (truly intended as syndication format)
+ */
+define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
+
+/**
+ * All RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_ALL', 255);
+
+/**
+ * Atom 0.3
+ */
+define('SIMPLEPIE_TYPE_ATOM_03', 256);
+
+/**
+ * Atom 1.0
+ */
+define('SIMPLEPIE_TYPE_ATOM_10', 512);
+
+/**
+ * All Atom
+ */
+define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
+
+/**
+ * All feed types
+ */
+define('SIMPLEPIE_TYPE_ALL', 1023);
+
+/**
+ * No construct
+ */
+define('SIMPLEPIE_CONSTRUCT_NONE', 0);
+
+/**
+ * Text construct
+ */
+define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
+
+/**
+ * HTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_HTML', 2);
+
+/**
+ * XHTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
+
+/**
+ * base64-encoded construct
+ */
+define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
+
+/**
+ * IRI construct
+ */
+define('SIMPLEPIE_CONSTRUCT_IRI', 16);
+
+/**
+ * A construct that might be HTML
+ */
+define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
+
+/**
+ * All constructs
+ */
+define('SIMPLEPIE_CONSTRUCT_ALL', 63);
+
+/**
+ * PCRE for HTML attributes
+ */
+define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
+
+/**
+ * PCRE for XML attributes
+ */
+define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
+
+/**
+ * XML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
+
+/**
+ * Atom 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
+
+/**
+ * Atom 0.3 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
+
+/**
+ * RDF Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+
+/**
+ * RSS 0.90 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
+
+/**
+ * RSS 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
+
+/**
+ * RSS 1.0 Content Module Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
+
+/**
+ * RSS 2.0 Namespace
+ * (Stupid, I know, but I'm certain it will confuse people less with support.)
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_20', '');
+
+/**
+ * DC 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
+
+/**
+ * DC 1.1 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
+
+/**
+ * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
+
+/**
+ * GeoRSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
+
+/**
+ * Media RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
+
+/**
+ * Wrong Media RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
+
+/**
+ * iTunes RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+
+/**
+ * XHTML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
+
+/**
+ * IANA Link Relations Registry
+ */
+define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
+
+/**
+ * Whether we're running on PHP5
+ */
+define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
+
+/**
+ * No file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
+
+/**
+ * Remote file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
+
+/**
+ * Local file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
+
+/**
+ * fsockopen() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
+
+/**
+ * cURL file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
+
+/**
+ * file_get_contents() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
+
+/**
+ * SimplePie
+ *
+ * @package SimplePie
+ * @version "Razzleberry"
+ * @copyright 2004-2007 Ryan Parman, Geoffrey Sneddon
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @todo Option for type of fetching (cache, not modified header, fetch, etc.)
+ */
+class SimplePie
+{
+ /**
+ * @var array Raw data
+ * @access private
+ */
+ var $data = array();
+
+ /**
+ * @var mixed Error string
+ * @access private
+ */
+ var $error;
+
+ /**
+ * @var object Instance of SimplePie_Sanitize (or other class)
+ * @see SimplePie::set_sanitize_class()
+ * @access private
+ */
+ var $sanitize;
+
+ /**
+ * @var string SimplePie Useragent
+ * @see SimplePie::set_useragent()
+ * @access private
+ */
+ var $useragent = SIMPLEPIE_USERAGENT;
+
+ /**
+ * @var string Feed URL
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ var $feed_url;
+
+ /**
+ * @var object Instance of SimplePie_File to use as a feed
+ * @see SimplePie::set_file()
+ * @access private
+ */
+ var $file;
+
+ /**
+ * @var string Raw feed data
+ * @see SimplePie::set_raw_data()
+ * @access private
+ */
+ var $raw_data;
+
+ /**
+ * @var int Timeout for fetching remote files
+ * @see SimplePie::set_timeout()
+ * @access private
+ */
+ var $timeout = 10;
+
+ /**
+ * @var bool Forces fsockopen() to be used for remote files instead
+ * of cURL, even if a new enough version is installed
+ * @see SimplePie::force_fsockopen()
+ * @access private
+ */
+ var $force_fsockopen = false;
+
+ /**
+ * @var bool Force the given data/URL to be treated as a feed no matter what
+ * it appears like
+ * @see SimplePie::force_feed()
+ * @access private
+ */
+ var $force_feed = false;
+
+ /**
+ * @var bool Enable/Disable XML dump
+ * @see SimplePie::enable_xml_dump()
+ * @access private
+ */
+ var $xml_dump = false;
+
+ /**
+ * @var bool Enable/Disable Caching
+ * @see SimplePie::enable_cache()
+ * @access private
+ */
+ var $cache = true;
+
+ /**
+ * @var int Cache duration (in seconds)
+ * @see SimplePie::set_cache_duration()
+ * @access private
+ */
+ var $cache_duration = 3600;
+
+ /**
+ * @var int Auto-discovery cache duration (in seconds)
+ * @see SimplePie::set_autodiscovery_cache_duration()
+ * @access private
+ */
+ var $autodiscovery_cache_duration = 604800; // 7 Days.
+
+ /**
+ * @var string Cache location (relative to executing script)
+ * @see SimplePie::set_cache_location()
+ * @access private
+ */
+ var $cache_location = './cache';
+
+ /**
+ * @var string Function that creates the cache filename
+ * @see SimplePie::set_cache_name_function()
+ * @access private
+ */
+ var $cache_name_function = 'md5';
+
+ /**
+ * @var bool Reorder feed by date descending
+ * @see SimplePie::enable_order_by_date()
+ * @access private
+ */
+ var $order_by_date = true;
+
+ /**
+ * @var mixed Force input encoding to be set to the follow value
+ * (false, or anything type-cast to false, disables this feature)
+ * @see SimplePie::set_input_encoding()
+ * @access private
+ */
+ var $input_encoding = false;
+
+ /**
+ * @var int Feed Autodiscovery Level
+ * @see SimplePie::set_autodiscovery_level()
+ * @access private
+ */
+ var $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
+
+ /**
+ * @var string Class used for caching feeds
+ * @see SimplePie::set_cache_class()
+ * @access private
+ */
+ var $cache_class = 'SimplePie_Cache';
+
+ /**
+ * @var string Class used for locating feeds
+ * @see SimplePie::set_locator_class()
+ * @access private
+ */
+ var $locator_class = 'SimplePie_Locator';
+
+ /**
+ * @var string Class used for parsing feeds
+ * @see SimplePie::set_parser_class()
+ * @access private
+ */
+ var $parser_class = 'SimplePie_Parser';
+
+ /**
+ * @var string Class used for fetching feeds
+ * @see SimplePie::set_file_class()
+ * @access private
+ */
+ var $file_class = 'SimplePie_File';
+
+ /**
+ * @var string Class used for items
+ * @see SimplePie::set_item_class()
+ * @access private
+ */
+ var $item_class = 'SimplePie_Item';
+
+ /**
+ * @var string Class used for authors
+ * @see SimplePie::set_author_class()
+ * @access private
+ */
+ var $author_class = 'SimplePie_Author';
+
+ /**
+ * @var string Class used for categories
+ * @see SimplePie::set_category_class()
+ * @access private
+ */
+ var $category_class = 'SimplePie_Category';
+
+ /**
+ * @var string Class used for enclosures
+ * @see SimplePie::set_enclosures_class()
+ * @access private
+ */
+ var $enclosure_class = 'SimplePie_Enclosure';
+
+ /**
+ * @var string Class used for Media RSS <media:text> captions
+ * @see SimplePie::set_caption_class()
+ * @access private
+ */
+ var $caption_class = 'SimplePie_Caption';
+
+ /**
+ * @var string Class used for Media RSS <media:copyright>
+ * @see SimplePie::set_copyright_class()
+ * @access private
+ */
+ var $copyright_class = 'SimplePie_Copyright';
+
+ /**
+ * @var string Class used for Media RSS <media:credit>
+ * @see SimplePie::set_credit_class()
+ * @access private
+ */
+ var $credit_class = 'SimplePie_Credit';
+
+ /**
+ * @var string Class used for Media RSS <media:rating>
+ * @see SimplePie::set_rating_class()
+ * @access private
+ */
+ var $rating_class = 'SimplePie_Rating';
+
+ /**
+ * @var string Class used for Media RSS <media:restriction>
+ * @see SimplePie::set_restriction_class()
+ * @access private
+ */
+ var $restriction_class = 'SimplePie_Restriction';
+
+ /**
+ * @var string Class used for content-type sniffing
+ * @see SimplePie::set_content_type_sniffer_class()
+ * @access private
+ */
+ var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
+
+ /**
+ * @var string Class used for item sources.
+ * @see SimplePie::set_source_class()
+ * @access private
+ */
+ var $source_class = 'SimplePie_Source';
+
+ /**
+ * @var mixed Set javascript query string parameter (false, or
+ * anything type-cast to false, disables this feature)
+ * @see SimplePie::set_javascript()
+ * @access private
+ */
+ var $javascript = 'js';
+
+ /**
+ * @var int Maximum number of feeds to check with autodiscovery
+ * @see SimplePie::set_max_checked_feeds()
+ * @access private
+ */
+ var $max_checked_feeds = 10;
+
+ /**
+ * @var string Web-accessible path to the handler_favicon.php file.
+ * @see SimplePie::set_favicon_handler()
+ * @access private
+ */
+ var $favicon_handler = '';
+
+ /**
+ * @var string Web-accessible path to the handler_image.php file.
+ * @see SimplePie::set_image_handler()
+ * @access private
+ */
+ var $image_handler = '';
+
+ /**
+ * @var array Stores the URLs when multiple feeds are being initialized.
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ var $multifeed_url = array();
+
+ /**
+ * @var array Stores SimplePie objects when multiple feeds initialized.
+ * @access private
+ */
+ var $multifeed_objects = array();
+
+ /**
+ * @var array Stores the get_object_vars() array for use with multifeeds.
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ var $config_settings = null;
+
+ /**
+ * @var integer Stores the number of items to return per-feed with multifeeds.
+ * @see SimplePie::set_item_limit()
+ * @access private
+ */
+ var $item_limit = 0;
+
+ /**
+ * @var array Stores the default attributes to be stripped by strip_attributes().
+ * @see SimplePie::strip_attributes()
+ * @access private
+ */
+ var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+
+ /**
+ * @var array Stores the default tags to be stripped by strip_htmltags().
+ * @see SimplePie::strip_htmltags()
+ * @access private
+ */
+ var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+
+ /**
+ * The SimplePie class contains feed level data and options
+ *
+ * There are two ways that you can create a new SimplePie object. The first
+ * is by passing a feed URL as a parameter to the SimplePie constructor
+ * (as well as optionally setting the cache location and cache expiry). This
+ * will initialise the whole feed with all of the default settings, and you
+ * can begin accessing methods and properties immediately.
+ *
+ * The second way is to create the SimplePie object with no parameters
+ * at all. This will enable you to set configuration options. After setting
+ * them, you must initialise the feed using $feed->init(). At that point the
+ * object's methods and properties will be available to you. This format is
+ * what is used throughout this documentation.
+ *
+ * @access public
+ * @since 1.0 Preview Release
+ * @param string $feed_url This is the URL you want to parse.
+ * @param string $cache_location This is where you want the cache to be stored.
+ * @param int $cache_duration This is the number of seconds that you want to store the cache file for.
+ */
+ function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null)
+ {
+ // Other objects, instances created here so we can set options on them
+ $this->sanitize =& new SimplePie_Sanitize;
+
+ // Set options if they're passed to the constructor
+ if ($cache_location !== null)
+ {
+ $this->set_cache_location($cache_location);
+ }
+
+ if ($cache_duration !== null)
+ {
+ $this->set_cache_duration($cache_duration);
+ }
+
+ // Only init the script if we're passed a feed URL
+ if ($feed_url !== null)
+ {
+ $this->set_feed_url($feed_url);
+ $this->init();
+ }
+ }
+
+ /**
+ * Used for converting object to a string
+ */
+ function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ /**
+ * Remove items that link back to this before destroying this object
+ */
+ function __destruct()
+ {
+ if (!empty($this->data['items']))
+ {
+ foreach ($this->data['items'] as $item)
+ {
+ $item->__destruct();
+ }
+ unset($this->data['items']);
+ }
+ if (!empty($this->data['ordered_items']))
+ {
+ foreach ($this->data['ordered_items'] as $item)
+ {
+ $item->__destruct();
+ }
+ unset($this->data['ordered_items']);
+ }
+ }
+
+ /**
+ * Force the given data/URL to be treated as a feed no matter what it
+ * appears like
+ *
+ * @access public
+ * @since 1.1
+ * @param bool $enable Force the given data/URL to be treated as a feed
+ */
+ function force_feed($enable = false)
+ {
+ $this->force_feed = (bool) $enable;
+ }
+
+ /**
+ * This is the URL of the feed you want to parse.
+ *
+ * This allows you to enter the URL of the feed you want to parse, or the
+ * website you want to try to use auto-discovery on. This takes priority
+ * over any set raw data.
+ *
+ * You can set multiple feeds to mash together by passing an array instead
+ * of a string for the $url. Remember that with each additional feed comes
+ * additional processing and resources.
+ *
+ * @access public
+ * @since 1.0 Preview Release
+ * @param mixed $url This is the URL (or array of URLs) that you want to parse.
+ * @see SimplePie::set_raw_data()
+ */
+ function set_feed_url($url)
+ {
+ if (is_array($url))
+ {
+ $this->multifeed_url = array();
+ foreach ($url as $value)
+ {
+ $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
+ }
+ }
+ else
+ {
+ $this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
+ }
+ }
+
+ /**
+ * Provides an instance of SimplePie_File to use as a feed
+ *
+ * @access public
+ * @param object &$file Instance of SimplePie_File (or subclass)
+ * @return bool True on success, false on failure
+ */
+ function set_file(&$file)
+ {
+ if (is_a($file, 'SimplePie_File'))
+ {
+ $this->feed_url = $file->url;
+ $this->file =& $file;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to use a string of RSS/Atom data instead of a remote feed.
+ *
+ * If you have a feed available as a string in PHP, you can tell SimplePie
+ * to parse that data string instead of a remote feed. Any set feed URL
+ * takes precedence.
+ *
+ * @access public
+ * @since 1.0 Beta 3
+ * @param string $data RSS or Atom data as a string.
+ * @see SimplePie::set_feed_url()
+ */
+ function set_raw_data($data)
+ {
+ $this->raw_data = $data;
+ }
+
+ /**
+ * Allows you to override the default timeout for fetching remote feeds.
+ *
+ * This allows you to change the maximum time the feed's server to respond
+ * and send the feed back.
+ *
+ * @access public
+ * @since 1.0 Beta 3
+ * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
+ */
+ function set_timeout($timeout = 10)
+ {
+ $this->timeout = (int) $timeout;
+ }
+
+ /**
+ * Forces SimplePie to use fsockopen() instead of the preferred cURL
+ * functions.
+ *
+ * @access public
+ * @since 1.0 Beta 3
+ * @param bool $enable Force fsockopen() to be used
+ */
+ function force_fsockopen($enable = false)
+ {
+ $this->force_fsockopen = (bool) $enable;
+ }
+
+ /**
+ * Outputs the raw XML content of the feed, after it has gone through
+ * SimplePie's filters.
+ *
+ * Used only for debugging, this function will output the XML content as
+ * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up
+ * before trying to parse it. Many parts of the feed are re-written in
+ * memory, and in the end, you have a parsable feed. XML dump shows you the
+ * actual XML that SimplePie tries to parse, which may or may not be very
+ * different from the original feed.
+ *
+ * @access public
+ * @since 1.0 Preview Release
+ * @param bool $enable Enable XML dump
+ */
+ function enable_xml_dump($enable = false)
+ {
+ $this->xml_dump = (bool) $enable;
+ }
+
+ /**
+ * Enables/disables caching in SimplePie.
+ *
+ * This option allows you to disable caching all-together in SimplePie.
+ * However, disabling the cache can lead to longer load times.
+ *
+ * @access public
+ * @since 1.0 Preview Release
+ * @param bool $enable Enable caching
+ */
+ function enable_cache($enable = true)
+ {
+ $this->cache = (bool) $enable;
+ }
+
+ /**
+ * Set the length of time (in seconds) that the contents of a feed
+ * will be cached.
+ *
+ * @access public
+ * @param int $seconds The feed content cache duration.
+ */
+ function set_cache_duration($seconds = 3600)
+ {
+ $this->cache_duration = (int) $seconds;
+ }
+
+ /**
+ * Set the length of time (in seconds) that the autodiscovered feed
+ * URL will be cached.
+ *
+ * @access public
+ * @param int $seconds The autodiscovered feed URL cache duration.
+ */
+ function set_autodiscovery_cache_duration($seconds = 604800)
+ {
+ $this->autodiscovery_cache_duration = (int) $seconds;
+ }
+
+ /**
+ * Set the file system location where the cached files should be stored.
+ *
+ * @access public
+ * @param string $location The file system location.
+ */
+ function set_cache_location($location = './cache')
+ {
+ $this->cache_location = (string) $location;
+ }
+
+ /**
+ * Determines whether feed items should be sorted into reverse chronological order.
+ *
+ * @access public
+ * @param bool $enable Sort as reverse chronological order.
+ */
+ function enable_order_by_date($enable = true)
+ {
+ $this->order_by_date = (bool) $enable;
+ }
+
+ /**
+ * Allows you to override the character encoding reported by the feed.
+ *
+ * @access public
+ * @param string $encoding Character encoding.
+ */
+ function set_input_encoding($encoding = false)
+ {
+ if ($encoding)
+ {
+ $this->input_encoding = (string) $encoding;
+ }
+ else
+ {
+ $this->input_encoding = false;
+ }
+ }
+
+ /**
+ * Set how much feed autodiscovery to do
+ *
+ * @access public
+ * @see SIMPLEPIE_LOCATOR_NONE
+ * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
+ * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
+ * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
+ * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
+ * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
+ * @see SIMPLEPIE_LOCATOR_ALL
+ * @param int $level Feed Autodiscovery Level (level can be a
+ * combination of the above constants, see bitwise OR operator)
+ */
+ function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
+ {
+ $this->autodiscovery = (int) $level;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for caching.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_cache_class($class = 'SimplePie_Cache')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
+ {
+ $this->cache_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for auto-discovery.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_locator_class($class = 'SimplePie_Locator')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
+ {
+ $this->locator_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for XML parsing.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_parser_class($class = 'SimplePie_Parser')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
+ {
+ $this->parser_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for remote file fetching.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_file_class($class = 'SimplePie_File')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
+ {
+ $this->file_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for data sanitization.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_sanitize_class($class = 'SimplePie_Sanitize')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
+ {
+ $this->sanitize =& new $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for handling feed items.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_item_class($class = 'SimplePie_Item')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
+ {
+ $this->item_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for handling author data.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_author_class($class = 'SimplePie_Author')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
+ {
+ $this->author_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for handling category data.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_category_class($class = 'SimplePie_Category')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
+ {
+ $this->category_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for feed enclosures.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_enclosure_class($class = 'SimplePie_Enclosure')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
+ {
+ $this->enclosure_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for <media:text> captions
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_caption_class($class = 'SimplePie_Caption')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
+ {
+ $this->caption_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for <media:copyright>
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_copyright_class($class = 'SimplePie_Copyright')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
+ {
+ $this->copyright_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for <media:credit>
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_credit_class($class = 'SimplePie_Credit')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
+ {
+ $this->credit_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for <media:rating>
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_rating_class($class = 'SimplePie_Rating')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
+ {
+ $this->rating_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for <media:restriction>
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_restriction_class($class = 'SimplePie_Restriction')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
+ {
+ $this->restriction_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses for content-type sniffing.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
+ {
+ $this->content_type_sniffer_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to change which class SimplePie uses item sources.
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @access public
+ * @param string $class Name of custom class.
+ * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ */
+ function set_source_class($class = 'SimplePie_Source')
+ {
+ if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
+ {
+ $this->source_class = $class;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allows you to override the default user agent string.
+ *
+ * @access public
+ * @param string $ua New user agent string.
+ */
+ function set_useragent($ua = SIMPLEPIE_USERAGENT)
+ {
+ $this->useragent = (string) $ua;
+ }
+
+ /**
+ * Set callback function to create cache filename with
+ *
+ * @access public
+ * @param mixed $function Callback function
+ */
+ function set_cache_name_function($function = 'md5')
+ {
+ if (is_callable($function))
+ {
+ $this->cache_name_function = $function;
+ }
+ }
+
+ /**
+ * Set javascript query string parameter
+ *
+ * @access public
+ * @param mixed $get Javascript query string parameter
+ */
+ function set_javascript($get = 'js')
+ {
+ if ($get)
+ {
+ $this->javascript = (string) $get;
+ }
+ else
+ {
+ $this->javascript = false;
+ }
+ }
+
+ /**
+ * Set options to make SP as fast as possible. Forgoes a
+ * substantial amount of data sanitization in favor of speed.
+ *
+ * @access public
+ * @param bool $set Whether to set them or not
+ */
+ function set_stupidly_fast($set = false)
+ {
+ if ($set)
+ {
+ $this->enable_order_by_date(false);
+ $this->remove_div(false);
+ $this->strip_comments(false);
+ $this->strip_htmltags(false);
+ $this->strip_attributes(false);
+ $this->set_image_handler(false);
+ }
+ }
+
+ /**
+ * Set maximum number of feeds to check with autodiscovery
+ *
+ * @access public
+ * @param int $max Maximum number of feeds to check
+ */
+ function set_max_checked_feeds($max = 10)
+ {
+ $this->max_checked_feeds = (int) $max;
+ }
+
+ function remove_div($enable = true)
+ {
+ $this->sanitize->remove_div($enable);
+ }
+
+ function strip_htmltags($tags = '', $encode = null)
+ {
+ if ($tags === '')
+ {
+ $tags = $this->strip_htmltags;
+ }
+ $this->sanitize->strip_htmltags($tags);
+ if ($encode !== null)
+ {
+ $this->sanitize->encode_instead_of_strip($tags);
+ }
+ }
+
+ function encode_instead_of_strip($enable = true)
+ {
+ $this->sanitize->encode_instead_of_strip($enable);
+ }
+
+ function strip_attributes($attribs = '')
+ {
+ if ($attribs === '')
+ {
+ $attribs = $this->strip_attributes;
+ }
+ $this->sanitize->strip_attributes($attribs);
+ }
+
+ function set_output_encoding($encoding = 'UTF-8')
+ {
+ $this->sanitize->set_output_encoding($encoding);
+ }
+
+ function strip_comments($strip = false)
+ {
+ $this->sanitize->strip_comments($strip);
+ }
+
+ /**
+ * Set element/attribute key/value pairs of HTML attributes
+ * containing URLs that need to be resolved relative to the feed
+ *
+ * @access public
+ * @since 1.0
+ * @param array $element_attribute Element/attribute key/value pairs
+ */
+ function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
+ {
+ $this->sanitize->set_url_replacements($element_attribute);
+ }
+
+ /**
+ * Set the handler to enable the display of cached favicons.
+ *
+ * @access public
+ * @param str $page Web-accessible path to the handler_favicon.php file.
+ * @param str $qs The query string that the value should be passed to.
+ */
+ function set_favicon_handler($page = false, $qs = 'i')
+ {
+ if ($page != false)
+ {
+ $this->favicon_handler = $page . '?' . $qs . '=';
+ }
+ else
+ {
+ $this->favicon_handler = '';
+ }
+ }
+
+ /**
+ * Set the handler to enable the display of cached images.
+ *
+ * @access public
+ * @param str $page Web-accessible path to the handler_image.php file.
+ * @param str $qs The query string that the value should be passed to.
+ */
+ function set_image_handler($page = false, $qs = 'i')
+ {
+ if ($page != false)
+ {
+ $this->sanitize->set_image_handler($page . '?' . $qs . '=');
+ }
+ else
+ {
+ $this->image_handler = '';
+ }
+ }
+
+ /**
+ * Set the limit for items returned per-feed with multifeeds.
+ *
+ * @access public
+ * @param integer $limit The maximum number of items to return.
+ */
+ function set_item_limit($limit = 0)
+ {
+ $this->item_limit = (int) $limit;
+ }
+
+ function init()
+ {
+ if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
+ {
+ return false;
+ }
+ if (isset($_GET[$this->javascript]))
+ {
+ if (function_exists('ob_gzhandler'))
+ {
+ ob_start('ob_gzhandler');
+ }
+ header('Content-type: text/javascript; charset: UTF-8');
+ header('Cache-Control: must-revalidate');
+ header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
+ ?>
+function embed_odeo(link) {
+ document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
+}
+
+function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
+ if (placeholder != '') {
+ document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+ }
+ else {
+ document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+ }
+}
+
+function embed_flash(bgcolor, width, height, link, loop, type) {
+ document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
+}
+
+function embed_flv(width, height, link, placeholder, loop, player) {
+ document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
+}
+
+function embed_wmedia(width, height, link) {
+ document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
+}
+ <?php
+ exit;
+ }
+
+ // Pass whatever was set with config options over to the sanitizer.
+ $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
+ $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
+
+ if ($this->feed_url !== null || $this->raw_data !== null)
+ {
+ $this->data = array();
+ $this->multifeed_objects = array();
+ $cache = false;
+
+ if ($this->feed_url !== null)
+ {
+ $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
+ // Decide whether to enable caching
+ if ($this->cache && $parsed_feed_url['scheme'] !== '')
+ {
+ $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
+ }
+ // If it's enabled and we don't want an XML dump, use the cache
+ if ($cache && !$this->xml_dump)
+ {
+ // Load the Cache
+ $this->data = $cache->load();
+ if (!empty($this->data))
+ {
+ // If the cache is for an outdated build of SimplePie
+ if (!isset($this->data['build']) || $this->data['build'] != SIMPLEPIE_BUILD)
+ {
+ $cache->unlink();
+ $this->data = array();
+ }
+ // If we've hit a collision just rerun it with caching disabled
+ elseif (isset($this->data['url']) && $this->data['url'] != $this->feed_url)
+ {
+ $cache = false;
+ $this->data = array();
+ }
+ // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
+ elseif (isset($this->data['feed_url']))
+ {
+ // If the autodiscovery cache is still valid use it.
+ if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
+ {
+ // Do not need to do feed autodiscovery yet.
+ if ($this->data['feed_url'] == $this->data['url'])
+ {
+ $cache->unlink();
+ $this->data = array();
+ }
+ else
+ {
+ $this->set_feed_url($this->data['feed_url']);
+ return $this->init();
+ }
+ }
+ }
+ // Check if the cache has been updated
+ elseif ($cache->mtime() + $this->cache_duration < time())
+ {
+ // If we have last-modified and/or etag set
+ if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
+ {
+ $headers = array();
+ if (isset($this->data['headers']['last-modified']))
+ {
+ $headers['if-modified-since'] = $this->data['headers']['last-modified'];
+ }
+ if (isset($this->data['headers']['etag']))
+ {
+ $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"';
+ }
+ $file =& new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
+ if ($file->success)
+ {
+ if ($file->status_code == 304)
+ {
+ $cache->touch();
+ return true;
+ }
+ else
+ {
+ $headers = $file->headers;
+ }
+ }
+ else
+ {
+ unset($file);
+ }
+ }
+ }
+ // If the cache is still valid, just return true
+ else
+ {
+ return true;
+ }
+ }
+ // If the cache is empty, delete it
+ else
+ {
+ $cache->unlink();
+ $this->data = array();
+ }
+ }
+ // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
+ if (!isset($file))
+ {
+ if (is_a($this->file, 'SimplePie_File') && $this->file->url == $this->feed_url)
+ {
+ $file =& $this->file;
+ }
+ else
+ {
+ $file =& new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
+ }
+ }
+ // If the file connection has an error, set SimplePie::error to that and quit
+ if (!$file->success)
+ {
+ $this->error = $file->error;
+ if (!empty($this->data))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (!$this->force_feed)
+ {
+ // Check if the supplied URL is a feed, if it isn't, look for it.
+ $locate =& new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
+ if (!$locate->is_feed($file))
+ {
+ // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
+ unset($file);
+ if ($file = $locate->find($this->autodiscovery))
+ {
+ if ($cache)
+ {
+ $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
+ if (!$cache->save($this))
+ {
+ trigger_error("$cache->name is not writeable", E_USER_WARNING);
+ }
+ $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
+ }
+ $this->feed_url = $file->url;
+ }
+ else
+ {
+ $this->error = "A feed could not be found at $this->feed_url";
+ SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ $locate = null;
+ }
+
+ $headers = $file->headers;
+ $data = $file->body;
+ $sniffer = new $this->content_type_sniffer_class($file);
+ $sniffed = $sniffer->get_type();
+ }
+ else
+ {
+ $data = $this->raw_data;
+ }
+
+ // Set up array of possible encodings
+ $encodings = array();
+
+ // First check to see if input has been overridden.
+ if ($this->input_encoding !== false)
+ {
+ $encodings[] = $this->input_encoding;
+ }
+
+ $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
+ $text_types = array('text/xml', 'text/xml-external-parsed-entity');
+
+ // RFC 3023 (only applies to sniffed content)
+ if (isset($sniffed))
+ {
+ if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = strtoupper($charset[1]);
+ }
+ $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
+ $encodings[] = 'UTF-8';
+ }
+ elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = $charset[1];
+ }
+ $encodings[] = 'US-ASCII';
+ }
+ // Text MIME-type default
+ elseif (substr($sniffed, 0, 5) === 'text/')
+ {
+ $encodings[] = 'US-ASCII';
+ }
+ }
+
+ // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
+ $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
+ $encodings[] = 'UTF-8';
+ $encodings[] = 'ISO-8859-1';
+
+ // There's no point in trying an encoding twice
+ $encodings = array_unique($encodings);
+
+ // If we want the XML, just output that with the most likely encoding and quit
+ if ($this->xml_dump)
+ {
+ header('Content-type: text/xml; charset=' . $encodings[0]);
+ echo $data;
+ exit;
+ }
+
+ // Loop through each possible encoding, till we return something, or run out of possibilities
+ foreach ($encodings as $encoding)
+ {
+ // Change the encoding to UTF-8 (as we always use UTF-8 internally)
+ if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'))
+ {
+ // Create new parser
+ $parser =& new $this->parser_class();
+
+ // If it's parsed fine
+ if ($parser->parse($utf8_data, 'UTF-8'))
+ {
+ $this->data = $parser->get_data();
+ if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
+ {
+ if (isset($headers))
+ {
+ $this->data['headers'] = $headers;
+ }
+ $this->data['build'] = SIMPLEPIE_BUILD;
+
+ // Cache the file if caching is enabled
+ if ($cache && !$cache->save($this))
+ {
+ trigger_error("$cache->name is not writeable", E_USER_WARNING);
+ }
+ return true;
+ }
+ else
+ {
+ $this->error = "A feed could not be found at $this->feed_url";
+ SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ }
+ }
+ // We have an error, just set SimplePie::error to it and quit
+ $this->error = sprintf('XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
+ SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+ return false;
+ }
+ elseif (!empty($this->multifeed_url))
+ {
+ $i = 0;
+ $success = 0;
+ $this->multifeed_objects = array();
+ foreach ($this->multifeed_url as $url)
+ {
+ if (SIMPLEPIE_PHP5)
+ {
+ // This keyword needs to defy coding standards for PHP4 compatibility
+ $this->multifeed_objects[$i] = clone($this);
+ }
+ else
+ {
+ $this->multifeed_objects[$i] = $this;
+ }
+ $this->multifeed_objects[$i]->set_feed_url($url);
+ $success |= $this->multifeed_objects[$i]->init();
+ $i++;
+ }
+ return (bool) $success;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the error message for the occurred error
+ *
+ * @access public
+ * @return string Error message
+ */
+ function error()
+ {
+ return $this->error;
+ }
+
+ function get_encoding()
+ {
+ return $this->sanitize->output_encoding;
+ }
+
+ function handle_content_type($mime = 'text/html')
+ {
+ if (!headers_sent())
+ {
+ $header = "Content-type: $mime;";
+ if ($this->get_encoding())
+ {
+ $header .= ' charset=' . $this->get_encoding();
+ }
+ else
+ {
+ $header .= ' charset=UTF-8';
+ }
+ header($header);
+ }
+ }
+
+ function get_type()
+ {
+ if (!isset($this->data['type']))
+ {
+ $this->data['type'] = SIMPLEPIE_TYPE_ALL;
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
+ }
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
+ }
+ }
+ elseif (isset($this->data['child']['']['rss']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
+ if (isset($this->data['child']['']['rss'][0]['attribs']['']['version']))
+ {
+ switch (trim($this->data['child']['']['rss'][0]['attribs']['']['version']))
+ {
+ case '0.91':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
+ if (isset($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data']))
+ {
+ switch (trim($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data']))
+ {
+ case '0':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
+ break;
+
+ case '24':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
+ break;
+ }
+ }
+ break;
+
+ case '0.92':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
+ break;
+
+ case '0.93':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
+ break;
+
+ case '0.94':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
+ break;
+
+ case '2.0':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $this->data['type'] = SIMPLEPIE_TYPE_NONE;
+ }
+ }
+ return $this->data['type'];
+ }
+
+ /**
+ * Returns the URL for the favicon of the feed's website.
+ *
+ * @todo Cache atom:icon
+ * @access public
+ * @since 1.0
+ */
+ function get_favicon()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url))
+ {
+ $favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url);
+
+ if ($this->cache && $this->favicon_handler)
+ {
+ $favicon_filename = call_user_func($this->cache_name_function, $favicon);
+ $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi');
+
+ if ($cache->load())
+ {
+ return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ $file =& new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
+
+ if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0)
+ {
+ $sniffer = new $this->content_type_sniffer_class($file);
+ if (substr($sniffer->get_type(), 0, 6) === 'image/')
+ {
+ if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
+ {
+ return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ trigger_error("$cache->name is not writeable", E_USER_WARNING);
+ return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @todo If we have a perm redirect we should return the new URL
+ * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+ * @todo Also, |atom:link|@rel=self
+ */
+ function subscribe_url()
+ {
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function subscribe_feed()
+ {
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function subscribe_outlook()
+ {
+ if ($this->feed_url !== null)
+ {
+ return 'outlook' . $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function subscribe_podcast()
+ {
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function subscribe_itunes()
+ {
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Creates the subscribe_* methods' return data
+ *
+ * @access private
+ * @param string $feed_url String to prefix to the feed URL
+ * @param string $site_url String to prefix to the site URL (and
+ * suffix to the feed URL)
+ * @return mixed URL if feed exists, false otherwise
+ */
+ function subscribe_service($feed_url, $site_url = null)
+ {
+ if ($this->subscribe_url())
+ {
+ $return = $this->sanitize($feed_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->feed_url);
+ if ($site_url !== null && $this->get_link() !== null)
+ {
+ $return .= $this->sanitize($site_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_link());
+ }
+ return $return;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function subscribe_aol()
+ {
+ return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url=');
+ }
+
+ function subscribe_bloglines()
+ {
+ return urldecode($this->subscribe_service('http://www.bloglines.com/sub/'));
+ }
+
+ function subscribe_eskobo()
+ {
+ return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage=');
+ }
+
+ function subscribe_feedfeeds()
+ {
+ return $this->subscribe_service('http://www.feedfeeds.com/add?feed=');
+ }
+
+ function subscribe_feedster()
+ {
+ return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=');
+ }
+
+ function subscribe_google()
+ {
+ return $this->subscribe_service('http://fusion.google.com/add?feedurl=');
+ }
+
+ function subscribe_gritwire()
+ {
+ return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=');
+ }
+
+ function subscribe_msn()
+ {
+ return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru=');
+ }
+
+ function subscribe_netvibes()
+ {
+ return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url=');
+ }
+
+ function subscribe_newsburst()
+ {
+ return $this->subscribe_service('http://www.newsburst.com/Source/?add=');
+ }
+
+ function subscribe_newsgator()
+ {
+ return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url=');
+ }
+
+ function subscribe_odeo()
+ {
+ return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed=');
+ }
+
+ function subscribe_podnova()
+ {
+ return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url=');
+ }
+
+ function subscribe_rojo()
+ {
+ return $this->subscribe_service('http://www.rojo.com/add-subscription?resource=');
+ }
+
+ function subscribe_yahoo()
+ {
+ return $this->subscribe_service('http://add.my.yahoo.com/rss?url=');
+ }
+
+ function get_feed_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_ATOM_10)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_ATOM_03)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_RDF)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if (isset($this->data['child']['']['rss'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child']['']['rss'][0]['child'][$namespace][$tag];
+ }
+ }
+ return null;
+ }
+
+ function get_channel_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
+ {
+ if ($return = $this->get_feed_tags($namespace, $tag))
+ {
+ return $return;
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_10)
+ {
+ if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_090)
+ {
+ if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if ($channel = $this->get_feed_tags('', 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ return null;
+ }
+
+ function get_image_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_RSS_10)
+ {
+ if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_090)
+ {
+ if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if ($image = $this->get_channel_tags('', 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ return null;
+ }
+
+ function get_base($element = array())
+ {
+ if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
+ {
+ return $element['xml_base'];
+ }
+ elseif ($this->get_link() !== null)
+ {
+ return $this->get_link();
+ }
+ else
+ {
+ return $this->subscribe_url();
+ }
+ }
+
+ function sanitize($data, $type, $base = '')
+ {
+ return $this->sanitize->sanitize($data, $type, $base);
+ }
+
+ function get_title()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags('', 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->category_class($term, $scheme, $label);
+ }
+ foreach ((array) $this->get_channel_tags('', 'category') as $category)
+ {
+ $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($categories))
+ {
+ return SimplePie_Misc::array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] =& new $this->author_class($name, $uri, $email);
+ }
+ }
+ if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] =& new $this->author_class($name, $url, $email);
+ }
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($authors))
+ {
+ return SimplePie_Misc::array_unique($authors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] =& new $this->author_class($name, $uri, $email);
+ }
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] =& new $this->author_class($name, $url, $email);
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return SimplePie_Misc::array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if (isset($links[$key]))
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Added for parity between the parent-level and the item/entry-level.
+ */
+ function get_permalink()
+ {
+ return $this->get_link(0);
+ }
+
+ function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_channel_tags('', 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if (SimplePie_Misc::is_isegment_nz_nc($key))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_description()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags('', 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_copyright()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags('', 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_language()
+ {
+ if ($return = $this->get_channel_tags('', 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['headers']['content-language']))
+ {
+ return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_latitude()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_longitude()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_title()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags('', 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_url()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+ {
+ return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags('', 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_link()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags('', 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_width()
+ {
+ if ($return = $this->get_image_tags('', 'width'))
+ {
+ return round($return[0]['data']);
+ }
+ elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url'))
+ {
+ return 88.0;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_height()
+ {
+ if ($return = $this->get_image_tags('', 'height'))
+ {
+ return round($return[0]['data']);
+ }
+ elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url'))
+ {
+ return 31.0;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_item_quantity($max = 0)
+ {
+ $qty = count($this->get_items());
+ if ($max == 0)
+ {
+ return $qty;
+ }
+ else
+ {
+ return ($qty > $max) ? $max : $qty;
+ }
+ }
+
+ function get_item($key = 0)
+ {
+ $items = $this->get_items();
+ if (isset($items[$key]))
+ {
+ return $items[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_items($start = 0, $end = 0)
+ {
+ if (!empty($this->multifeed_objects))
+ {
+ return SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
+ }
+ elseif (!isset($this->data['items']))
+ {
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] =& new $this->item_class($this, $items[$key]);
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] =& new $this->item_class($this, $items[$key]);
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] =& new $this->item_class($this, $items[$key]);
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] =& new $this->item_class($this, $items[$key]);
+ }
+ }
+ if ($items = $this->get_channel_tags('', 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] =& new $this->item_class($this, $items[$key]);
+ }
+ }
+ }
+
+ if (!empty($this->data['items']))
+ {
+ // If we want to order it by date, check if all items have a date, and then sort it
+ if ($this->order_by_date)
+ {
+ if (!isset($this->data['ordered_items']))
+ {
+ $do_sort = true;
+ foreach ($this->data['items'] as $item)
+ {
+ if (!$item->get_date('U'))
+ {
+ $do_sort = false;
+ break;
+ }
+ }
+ $item = null;
+ $this->data['ordered_items'] = $this->data['items'];
+ if ($do_sort)
+ {
+ usort($this->data['ordered_items'], array(&$this, 'sort_items'));
+ }
+ }
+ $items = $this->data['ordered_items'];
+ }
+ else
+ {
+ $items = $this->data['items'];
+ }
+
+ // Slice the data as desired
+ if ($end == 0)
+ {
+ return array_slice($items, $start);
+ }
+ else
+ {
+ return array_slice($items, $start, $end);
+ }
+ }
+ else
+ {
+ return array();
+ }
+ }
+
+ function sort_items($a, $b)
+ {
+ return $a->get_date('U') <= $b->get_date('U');
+ }
+
+ function merge_items($urls, $start = 0, $end = 0, $limit = 0)
+ {
+ if (is_array($urls) && sizeof($urls) > 0)
+ {
+ $items = array();
+ foreach ($urls as $arg)
+ {
+ if (is_a($arg, 'SimplePie'))
+ {
+ $items = array_merge($items, $arg->get_items(0, $limit));
+ }
+ else
+ {
+ trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
+ }
+ }
+
+ $do_sort = true;
+ foreach ($items as $item)
+ {
+ if (!$item->get_date('U'))
+ {
+ $do_sort = false;
+ break;
+ }
+ }
+ $item = null;
+ if ($do_sort)
+ {
+ usort($items, array('SimplePie', 'sort_items'));
+ }
+
+ if ($end == 0)
+ {
+ return array_slice($items, $start);
+ }
+ else
+ {
+ return array_slice($items, $start, $end);
+ }
+ }
+ else
+ {
+ trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
+ return array();
+ }
+ }
+}
+
+class SimplePie_Item
+{
+ var $feed;
+ var $data = array();
+
+ function SimplePie_Item($feed, $data)
+ {
+ $this->feed = $feed;
+ $this->data = $data;
+ }
+
+ function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ /**
+ * Remove items that link back to this before destroying this object
+ */
+ function __destruct()
+ {
+ unset($this->feed);
+ }
+
+ function get_item_tags($namespace, $tag)
+ {
+ if (isset($this->data['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][$namespace][$tag];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_base($element = array())
+ {
+ return $this->feed->get_base($element);
+ }
+
+ function sanitize($data, $type, $base = '')
+ {
+ return $this->feed->sanitize($data, $type, $base);
+ }
+
+ function get_feed()
+ {
+ return $this->feed;
+ }
+
+ function get_id($hash = false)
+ {
+ if (!$hash)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags('', 'guid'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (($return = $this->get_permalink()) !== null)
+ {
+ return $return;
+ }
+ elseif (($return = $this->get_title()) !== null)
+ {
+ return $return;
+ }
+ }
+ if ($this->get_permalink() !== null || $this->get_title() !== null)
+ {
+ return md5($this->get_permalink() . $this->get_title());
+ }
+ else
+ {
+ return md5(serialize($this->data));
+ }
+ }
+
+ function get_title()
+ {
+ if (!isset($this->data['title']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags('', 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $this->data['title'] = null;
+ }
+ }
+ return $this->data['title'];
+ }
+
+ function get_description($description_only = false)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags('', 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (!$description_only)
+ {
+ return $this->get_content(true);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_content($content_only = false)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif (!$content_only)
+ {
+ return $this->get_description(true);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ foreach ((array) $this->get_item_tags('', 'category') as $category)
+ {
+ $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($categories))
+ {
+ return SimplePie_Misc::array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] =& new $this->feed->author_class($name, $uri, $email);
+ }
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] =& new $this->feed->author_class($name, $url, $email);
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return SimplePie_Misc::array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * @todo Atom inheritance (item author, source author, feed author)
+ */
+ function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] =& new $this->feed->author_class($name, $uri, $email);
+ }
+ }
+ if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] =& new $this->feed->author_class($name, $url, $email);
+ }
+ }
+ if ($author = $this->get_item_tags('', 'author'))
+ {
+ $authors[] =& new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($authors))
+ {
+ return SimplePie_Misc::array_unique($authors);
+ }
+ elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
+ {
+ return $authors;
+ }
+ elseif ($authors = $this->feed->get_authors())
+ {
+ return $authors;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_copyright()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_date($date_format = 'j F Y, g:i a')
+ {
+ if (!isset($this->data['date']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags('', 'pubDate'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+
+ if (!empty($this->data['date']['raw']))
+ {
+ $parser = SimplePie_Parse_Date::get();
+ $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
+ }
+ else
+ {
+ $this->data['date'] = null;
+ }
+ }
+ if ($this->data['date'])
+ {
+ $date_format = (string) $date_format;
+ switch ($date_format)
+ {
+ case '':
+ return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
+
+ case 'U':
+ return $this->data['date']['parsed'];
+
+ default:
+ return date($date_format, $this->data['date']['parsed']);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_local_date($date_format = '%c')
+ {
+ if (!$date_format)
+ {
+ return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (($date = $this->get_date('U')) !== null)
+ {
+ return strftime($date_format, $date);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_permalink()
+ {
+ $link = $this->get_link();
+ $enclosure = $this->get_enclosure(0);
+ if ($link !== null)
+ {
+ return $link;
+ }
+ elseif ($enclosure !== null)
+ {
+ return $enclosure->get_link();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if ($links[$key] !== null)
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags('', 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags('', 'guid'))
+ {
+ if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) == 'true')
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if (SimplePie_Misc::is_isegment_nz_nc($key))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * @todo Add ability to prefer one type of content over another (in a media group).
+ */
+ function get_enclosure($key = 0, $prefer = null)
+ {
+ $enclosures = $this->get_enclosures();
+ if (isset($enclosures[$key]))
+ {
+ return $enclosures[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Grabs all available enclosures (podcasts, etc.)
+ *
+ * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
+ *
+ * At this point, we're pretty much assuming that all enclosures for an item are the same content. Anything else is too complicated to properly support.
+ *
+ * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
+ * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
+ */
+ function get_enclosures()
+ {
+ if (!isset($this->data['enclosures']))
+ {
+ $this->data['enclosures'] = array();
+
+ // Elements
+ $captions_parent = null;
+ $categories_parent = null;
+ $copyrights_parent = null;
+ $credits_parent = null;
+ $description_parent = null;
+ $duration_parent = null;
+ $hashes_parent = null;
+ $keywords_parent = null;
+ $player_parent = null;
+ $ratings_parent = null;
+ $restrictions_parent = null;
+ $thumbnails_parent = null;
+ $title_parent = null;
+
+ // Let's do the channel and item-level ones first, and just re-use them if we need to.
+ $parent = $this->get_feed();
+
+ // CAPTIONS
+ if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+ {
+ foreach ($captions as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ }
+ }
+ elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+ {
+ foreach ($captions as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ }
+ }
+ if (is_array($captions_parent))
+ {
+ $captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent));
+ }
+
+ // CATEGORIES
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
+ {
+ $term = null;
+ $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
+ $label = null;
+ if (isset($category['attribs']['']['text']))
+ {
+ $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+
+ if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
+ {
+ foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
+ {
+ if (isset($subcategory['attribs']['']['text']))
+ {
+ $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ }
+ }
+ if (is_array($categories_parent))
+ {
+ $categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent));
+ }
+
+ // COPYRIGHT
+ if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($copyright[0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($copyright[0]['data']))
+ {
+ $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+ }
+ elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($copyright[0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($copyright[0]['data']))
+ {
+ $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+ }
+
+ // CREDITS
+ if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+ {
+ foreach ($credits as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ }
+ }
+ elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+ {
+ foreach ($credits as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ }
+ }
+ if (is_array($credits_parent))
+ {
+ $credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent));
+ }
+
+ // DESCRIPTION
+ if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+ {
+ if (isset($description_parent[0]['data']))
+ {
+ $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+ elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+ {
+ if (isset($description_parent[0]['data']))
+ {
+ $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+
+ // DURATION
+ if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
+ {
+ $seconds = null;
+ $minutes = null;
+ $hours = null;
+ if (isset($duration_parent[0]['data']))
+ {
+ $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ if (sizeof($temp) > 0)
+ {
+ (int) $seconds = array_pop($temp);
+ }
+ if (sizeof($temp) > 0)
+ {
+ (int) $minutes = array_pop($temp);
+ $seconds += $minutes * 60;
+ }
+ if (sizeof($temp) > 0)
+ {
+ (int) $hours = array_pop($temp);
+ $seconds += $hours * 3600;
+ }
+ unset($temp);
+ $duration_parent = $seconds;
+ }
+ }
+
+ // HASHES
+ if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+ {
+ foreach ($hashes_iterator as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes_parent[] = $algo.':'.$value;
+ }
+ }
+ elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+ {
+ foreach ($hashes_iterator as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes_parent[] = $algo.':'.$value;
+ }
+ }
+ if (is_array($hashes_parent))
+ {
+ $hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent));
+ }
+
+ // KEYWORDS
+ if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ if (is_array($keywords_parent))
+ {
+ $keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent));
+ }
+
+ // PLAYER
+ if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+ {
+ if (isset($player_parent[0]['attribs']['']['url']))
+ {
+ $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+ {
+ if (isset($player_parent[0]['attribs']['']['url']))
+ {
+ $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+
+ // RATINGS
+ if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ }
+ elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = 'urn:itunes';
+ $rating_value = null;
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ }
+ elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ }
+ elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = 'urn:itunes';
+ $rating_value = null;
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ }
+ if (is_array($ratings_parent))
+ {
+ $ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent));
+ }
+
+ // RESTRICTIONS
+ if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ }
+ elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = 'allow';
+ $restriction_type = null;
+ $restriction_value = 'itunes';
+ if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes')
+ {
+ $restriction_relationship = 'deny';
+ }
+ $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ }
+ elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ }
+ elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = 'allow';
+ $restriction_type = null;
+ $restriction_value = 'itunes';
+ if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes')
+ {
+ $restriction_relationship = 'deny';
+ }
+ $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ }
+ if (is_array($restrictions_parent))
+ {
+ $restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent));
+ }
+
+ // THUMBNAILS
+ if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+ {
+ foreach ($thumbnails as $thumbnail)
+ {
+ if (isset($thumbnail['attribs']['']['url']))
+ {
+ $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ }
+ elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+ {
+ foreach ($thumbnails as $thumbnail)
+ {
+ if (isset($thumbnail['attribs']['']['url']))
+ {
+ $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ }
+
+ // TITLES
+ if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+ {
+ if (isset($title_parent[0]['data']))
+ {
+ $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+ elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+ {
+ if (isset($title_parent[0]['data']))
+ {
+ $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+
+ // Clear the memory
+ unset($parent);
+
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // If we have media:group tags, loop through them.
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
+ {
+ // If we have media:content tags, loop through them.
+ foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+ {
+ if (isset($content['attribs']['']['url']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // Start checking the attributes of media:content
+ if (isset($content['attribs']['']['bitrate']))
+ {
+ $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['channels']))
+ {
+ $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['duration']))
+ {
+ $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $duration = $duration_parent;
+ }
+ if (isset($content['attribs']['']['expression']))
+ {
+ $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['framerate']))
+ {
+ $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['height']))
+ {
+ $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['lang']))
+ {
+ $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['fileSize']))
+ {
+ $length = ceil($content['attribs']['']['fileSize']);
+ }
+ if (isset($content['attribs']['']['medium']))
+ {
+ $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['samplingrate']))
+ {
+ $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['type']))
+ {
+ $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['width']))
+ {
+ $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+
+ // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+ // CAPTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(SimplePie_Misc::array_unique($captions));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(SimplePie_Misc::array_unique($captions));
+ }
+ }
+ else
+ {
+ $captions = $captions_parent;
+ }
+
+ // CATEGORIES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ }
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ }
+ if (is_array($categories) && is_array($categories_parent))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+ }
+ elseif (is_array($categories))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique($categories));
+ }
+ elseif (is_array($categories_parent))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+ }
+
+ // COPYRIGHTS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+ }
+ else
+ {
+ $copyrights = $copyrights_parent;
+ }
+
+ // CREDITS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(SimplePie_Misc::array_unique($credits));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(SimplePie_Misc::array_unique($credits));
+ }
+ }
+ else
+ {
+ $credits = $credits_parent;
+ }
+
+ // DESCRIPTION
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $description = $description_parent;
+ }
+
+ // HASHES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ }
+ }
+ else
+ {
+ $hashes = $hashes_parent;
+ }
+
+ // KEYWORDS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ }
+ }
+ else
+ {
+ $keywords = $keywords_parent;
+ }
+
+ // PLAYER
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ $player = $player_parent;
+ }
+
+ // RATINGS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ }
+ }
+ else
+ {
+ $ratings = $ratings_parent;
+ }
+
+ // RESTRICTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ }
+ }
+ else
+ {
+ $restrictions = $restrictions_parent;
+ }
+
+ // THUMBNAILS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ }
+ }
+ else
+ {
+ $thumbnails = $thumbnails_parent;
+ }
+
+ // TITLES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $title = $title_parent;
+ }
+
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+ }
+ }
+ }
+
+ // If we have standalone media:content tags, loop through them.
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
+ {
+ foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+ {
+ if (isset($content['attribs']['']['url']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // Start checking the attributes of media:content
+ if (isset($content['attribs']['']['bitrate']))
+ {
+ $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['channels']))
+ {
+ $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['duration']))
+ {
+ $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $duration = $duration_parent;
+ }
+ if (isset($content['attribs']['']['expression']))
+ {
+ $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['framerate']))
+ {
+ $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['height']))
+ {
+ $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['lang']))
+ {
+ $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['fileSize']))
+ {
+ $length = ceil($content['attribs']['']['fileSize']);
+ }
+ if (isset($content['attribs']['']['medium']))
+ {
+ $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['samplingrate']))
+ {
+ $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['type']))
+ {
+ $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['width']))
+ {
+ $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+
+ // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+ // CAPTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(SimplePie_Misc::array_unique($captions));
+ }
+ }
+ else
+ {
+ $captions = $captions_parent;
+ }
+
+ // CATEGORIES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->feed->category_class($term, $scheme, $label);
+ }
+ }
+ if (is_array($categories) && is_array($categories_parent))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+ }
+ elseif (is_array($categories))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique($categories));
+ }
+ elseif (is_array($categories_parent))
+ {
+ $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+ }
+ else
+ {
+ $categories = null;
+ }
+
+ // COPYRIGHTS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+ }
+ else
+ {
+ $copyrights = $copyrights_parent;
+ }
+
+ // CREDITS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(SimplePie_Misc::array_unique($credits));
+ }
+ }
+ else
+ {
+ $credits = $credits_parent;
+ }
+
+ // DESCRIPTION
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $description = $description_parent;
+ }
+
+ // HASHES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ }
+ }
+ else
+ {
+ $hashes = $hashes_parent;
+ }
+
+ // KEYWORDS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ }
+ }
+ else
+ {
+ $keywords = $keywords_parent;
+ }
+
+ // PLAYER
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ $player = $player_parent;
+ }
+
+ // RATINGS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ }
+ }
+ else
+ {
+ $ratings = $ratings_parent;
+ }
+
+ // RESTRICTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ }
+ }
+ else
+ {
+ $restrictions = $restrictions_parent;
+ }
+
+ // THUMBNAILS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ }
+ }
+ else
+ {
+ $thumbnails = $thumbnails_parent;
+ }
+
+ // TITLES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $title = $title_parent;
+ }
+
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+ }
+ }
+ }
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure')
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ if (isset($link['attribs']['']['type']))
+ {
+ $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($link['attribs']['']['length']))
+ {
+ $length = ceil($link['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ }
+ }
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure')
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ if (isset($link['attribs']['']['type']))
+ {
+ $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($link['attribs']['']['length']))
+ {
+ $length = ceil($link['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ }
+ }
+
+ if ($enclosure = $this->get_item_tags('', 'enclosure'))
+ {
+ if (isset($enclosure[0]['attribs']['']['url']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
+ if (isset($enclosure[0]['attribs']['']['type']))
+ {
+ $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($enclosure[0]['attribs']['']['length']))
+ {
+ $length = ceil($enclosure[0]['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ }
+ }
+
+ if (sizeof($this->data['enclosures']) == 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
+ {
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ }
+
+ $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
+ }
+ if (!empty($this->data['enclosures']))
+ {
+ return $this->data['enclosures'];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_latitude()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_longitude()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_source()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
+ {
+ return new $this->feed->source_class($this, $return[0]);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Creates the add_to_* methods' return data
+ *
+ * @access private
+ * @param string $item_url String to prefix to the item permalink
+ * @param string $title_url String to prefix to the item title
+ * (and suffix to the item permalink)
+ * @return mixed URL if feed exists, false otherwise
+ */
+ function add_to_service($item_url, $title_url = null, $summary_url = null)
+ {
+ if ($this->get_permalink() !== null)
+ {
+ $return = $this->sanitize($item_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_permalink());
+ if ($title_url !== null && $this->get_title() !== null)
+ {
+ $return .= $this->sanitize($title_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_title());
+ }
+ if ($summary_url !== null && $this->get_description() !== null)
+ {
+ $return .= $this->sanitize($summary_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_description());
+ }
+ return $return;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function add_to_blinklist()
+ {
+ return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title=');
+ }
+
+ function add_to_blogmarks()
+ {
+ return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title=');
+ }
+
+ function add_to_delicious()
+ {
+ return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title=');
+ }
+
+ function add_to_digg()
+ {
+ return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext=');
+ }
+
+ function add_to_furl()
+ {
+ return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t=');
+ }
+
+ function add_to_magnolia()
+ {
+ return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title=');
+ }
+
+ function add_to_myweb20()
+ {
+ return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t=');
+ }
+
+ function add_to_newsvine()
+ {
+ return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h=');
+ }
+
+ function add_to_reddit()
+ {
+ return $this->add_to_service('http://reddit.com/submit?url=', '&title=');
+ }
+
+ function add_to_segnalo()
+ {
+ return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title=');
+ }
+
+ function add_to_simpy()
+ {
+ return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title=');
+ }
+
+ function add_to_spurl()
+ {
+ return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title=');
+ }
+
+ function add_to_wists()
+ {
+ return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title=');
+ }
+
+ function search_technorati()
+ {
+ return $this->add_to_service('http://www.technorati.com/search/');
+ }
+}
+
+class SimplePie_Source
+{
+ var $item;
+ var $data = array();
+
+ function SimplePie_Source($item, $data)
+ {
+ $this->item = $item;
+ $this->data = $data;
+ }
+
+ function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ /**
+ * Remove items that link back to this before destroying this object
+ */
+ function __destruct()
+ {
+ unset($this->item);
+ }
+
+ function get_source_tags($namespace, $tag)
+ {
+ if (isset($this->data['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][$namespace][$tag];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_base($element = array())
+ {
+ return $this->item->get_base($element);
+ }
+
+ function sanitize($data, $type, $base = '')
+ {
+ return $this->item->sanitize($data, $type, $base);
+ }
+
+ function get_item()
+ {
+ return $this->item;
+ }
+
+ function get_title()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags('', 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] =& new $this->item->feed->category_class($term, $scheme, $label);
+ }
+ foreach ((array) $this->get_source_tags('', 'category') as $category)
+ {
+ $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($categories))
+ {
+ return SimplePie_Misc::array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] =& new $this->item->feed->author_class($name, $uri, $email);
+ }
+ }
+ if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] =& new $this->item->feed->author_class($name, $url, $email);
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ }
+
+ if (!empty($authors))
+ {
+ return SimplePie_Misc::array_unique($authors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] =& new $this->item->feed->author_class($name, $uri, $email);
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] =& new $this->item->feed->author_class($name, $url, $email);
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return SimplePie_Misc::array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if (isset($links[$key]))
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Added for parity between the parent-level and the item/entry-level.
+ */
+ function get_permalink()
+ {
+ return $this->get_link(0);
+ }
+
+ function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags('', 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if (SimplePie_Misc::is_isegment_nz_nc($key))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_description()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags('', 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_copyright()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags('', 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_language()
+ {
+ if ($return = $this->get_source_tags('', 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['xml_lang']))
+ {
+ return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_latitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_longitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_image_url()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+ {
+ return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Author
+{
+ var $name;
+ var $link;
+ var $email;
+
+ // Constructor, used to input the data
+ function SimplePie_Author($name = null, $link = null, $email = null)
+ {
+ $this->name = $name;
+ $this->link = $link;
+ $this->email = $email;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return $this->link;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_email()
+ {
+ if ($this->email !== null)
+ {
+ return $this->email;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Category
+{
+ var $term;
+ var $scheme;
+ var $label;
+
+ // Constructor, used to input the data
+ function SimplePie_Category($term = null, $scheme = null, $label = null)
+ {
+ $this->term = $term;
+ $this->scheme = $scheme;
+ $this->label = $label;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_term()
+ {
+ if ($this->term !== null)
+ {
+ return $this->term;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_label()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return $this->get_term();
+ }
+ }
+}
+
+class SimplePie_Enclosure
+{
+ var $bitrate;
+ var $captions;
+ var $categories;
+ var $channels;
+ var $copyright;
+ var $credits;
+ var $description;
+ var $duration;
+ var $expression;
+ var $framerate;
+ var $handler;
+ var $hashes;
+ var $height;
+ var $javascript;
+ var $keywords;
+ var $lang;
+ var $length;
+ var $link;
+ var $medium;
+ var $player;
+ var $ratings;
+ var $restrictions;
+ var $samplingrate;
+ var $thumbnails;
+ var $title;
+ var $type;
+ var $width;
+
+ // Constructor, used to input the data
+ function SimplePie_Enclosure($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
+ {
+ $this->bitrate = $bitrate;
+ $this->captions = $captions;
+ $this->categories = $categories;
+ $this->channels = $channels;
+ $this->copyright = $copyright;
+ $this->credits = $credits;
+ $this->description = $description;
+ $this->duration = $duration;
+ $this->expression = $expression;
+ $this->framerate = $framerate;
+ $this->hashes = $hashes;
+ $this->height = $height;
+ $this->javascript = $javascript;
+ $this->keywords = $keywords;
+ $this->lang = $lang;
+ $this->length = $length;
+ $this->link = $link;
+ $this->medium = $medium;
+ $this->player = $player;
+ $this->ratings = $ratings;
+ $this->restrictions = $restrictions;
+ $this->samplingrate = $samplingrate;
+ $this->thumbnails = $thumbnails;
+ $this->title = $title;
+ $this->type = $type;
+ $this->width = $width;
+ if (class_exists('idna_convert'))
+ {
+ $idn =& new idna_convert;
+ $parsed = SimplePie_Misc::parse_url($link);
+ $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->handler = $this->get_handler(); // Needs to load last
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_bitrate()
+ {
+ if ($this->bitrate !== null)
+ {
+ return $this->bitrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_caption($key = 0)
+ {
+ $captions = $this->get_captions();
+ if (isset($captions[$key]))
+ {
+ return $captions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_captions()
+ {
+ if ($this->captions !== null)
+ {
+ return $this->captions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_categories()
+ {
+ if ($this->categories !== null)
+ {
+ return $this->categories;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_channels()
+ {
+ if ($this->channels !== null)
+ {
+ return $this->channels;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_copyright()
+ {
+ if ($this->copyright !== null)
+ {
+ return $this->copyright;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_credit($key = 0)
+ {
+ $credits = $this->get_credits();
+ if (isset($credits[$key]))
+ {
+ return $credits[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_credits()
+ {
+ if ($this->credits !== null)
+ {
+ return $this->credits;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_description()
+ {
+ if ($this->description !== null)
+ {
+ return $this->description;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_duration($convert = false)
+ {
+ if ($this->duration !== null)
+ {
+ if ($convert)
+ {
+ $time = SimplePie_Misc::time_hms($this->duration);
+ return $time;
+ }
+ else
+ {
+ return $this->duration;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_expression()
+ {
+ if ($this->expression !== null)
+ {
+ return $this->expression;
+ }
+ else
+ {
+ return 'full';
+ }
+ }
+
+ function get_extension()
+ {
+ if ($this->link !== null)
+ {
+ $url = SimplePie_Misc::parse_url($this->link);
+ if ($url['path'] !== '')
+ {
+ return pathinfo($url['path'], PATHINFO_EXTENSION);
+ }
+ }
+ return null;
+ }
+
+ function get_framerate()
+ {
+ if ($this->framerate !== null)
+ {
+ return $this->framerate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_handler()
+ {
+ return $this->get_real_type(true);
+ }
+
+ function get_hash($key = 0)
+ {
+ $hashes = $this->get_hashes();
+ if (isset($hashes[$key]))
+ {
+ return $hashes[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_hashes()
+ {
+ if ($this->hashes !== null)
+ {
+ return $this->hashes;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_height()
+ {
+ if ($this->height !== null)
+ {
+ return $this->height;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_keyword($key = 0)
+ {
+ $keywords = $this->get_keywords();
+ if (isset($keywords[$key]))
+ {
+ return $keywords[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_keywords()
+ {
+ if ($this->keywords !== null)
+ {
+ return $this->keywords;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_length()
+ {
+ if ($this->length !== null)
+ {
+ return $this->length;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return urldecode($this->link);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_medium()
+ {
+ if ($this->medium !== null)
+ {
+ return $this->medium;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_player()
+ {
+ if ($this->player !== null)
+ {
+ return $this->player;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_rating($key = 0)
+ {
+ $ratings = $this->get_ratings();
+ if (isset($ratings[$key]))
+ {
+ return $ratings[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_ratings()
+ {
+ if ($this->ratings !== null)
+ {
+ return $this->ratings;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_restriction($key = 0)
+ {
+ $restrictions = $this->get_restrictions();
+ if (isset($restrictions[$key]))
+ {
+ return $restrictions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_restrictions()
+ {
+ if ($this->restrictions !== null)
+ {
+ return $this->restrictions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_sampling_rate()
+ {
+ if ($this->samplingrate !== null)
+ {
+ return $this->samplingrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_size()
+ {
+ $length = $this->get_length();
+ if ($length !== null)
+ {
+ return round($length/1048576, 2);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_thumbnail($key = 0)
+ {
+ $thumbnails = $this->get_thumbnails();
+ if (isset($thumbnails[$key]))
+ {
+ return $thumbnails[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_thumbnails()
+ {
+ if ($this->thumbnails !== null)
+ {
+ return $this->thumbnails;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_title()
+ {
+ if ($this->title !== null)
+ {
+ return $this->title;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_width()
+ {
+ if ($this->width !== null)
+ {
+ return $this->width;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function native_embed($options='')
+ {
+ return $this->embed($options, true);
+ }
+
+ /**
+ * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
+ */
+ function embed($options = '', $native = false)
+ {
+ // Set up defaults
+ $audio = '';
+ $video = '';
+ $alt = '';
+ $altclass = '';
+ $loop = 'false';
+ $width = 'auto';
+ $height = 'auto';
+ $bgcolor = '#ffffff';
+ $mediaplayer = '';
+ $widescreen = false;
+ $handler = $this->get_handler();
+ $type = $this->get_real_type();
+
+ // Process options and reassign values as necessary
+ if (is_array($options))
+ {
+ extract($options);
+ }
+ else
+ {
+ $options = explode(',', $options);
+ foreach($options as $option)
+ {
+ $opt = explode(':', $option, 2);
+ if (isset($opt[0], $opt[1]))
+ {
+ $opt[0] = trim($opt[0]);
+ $opt[1] = trim($opt[1]);
+ switch ($opt[0])
+ {
+ case 'audio':
+ $audio = $opt[1];
+ break;
+
+ case 'video':
+ $video = $opt[1];
+ break;
+
+ case 'alt':
+ $alt = $opt[1];
+ break;
+
+ case 'altclass':
+ $altclass = $opt[1];
+ break;
+
+ case 'loop':
+ $loop = $opt[1];
+ break;
+
+ case 'width':
+ $width = $opt[1];
+ break;
+
+ case 'height':
+ $height = $opt[1];
+ break;
+
+ case 'bgcolor':
+ $bgcolor = $opt[1];
+ break;
+
+ case 'mediaplayer':
+ $mediaplayer = $opt[1];
+ break;
+
+ case 'widescreen':
+ $widescreen = $opt[1];
+ break;
+ }
+ }
+ }
+ }
+
+ $mime = explode('/', $type, 2);
+ $mime = $mime[0];
+
+ // Process values for 'auto'
+ if ($width == 'auto')
+ {
+ if ($mime == 'video')
+ {
+ if ($height == 'auto')
+ {
+ $width = 480;
+ }
+ elseif ($widescreen)
+ {
+ $width = round((intval($height)/9)*16);
+ }
+ else
+ {
+ $width = round((intval($height)/3)*4);
+ }
+ }
+ else
+ {
+ $width = '100%';
+ }
+ }
+
+ if ($height == 'auto')
+ {
+ if ($mime == 'audio')
+ {
+ $height = 0;
+ }
+ elseif ($mime == 'video')
+ {
+ if ($width == 'auto')
+ {
+ if ($widescreen)
+ {
+ $height = 270;
+ }
+ else
+ {
+ $height = 360;
+ }
+ }
+ elseif ($widescreen)
+ {
+ $height = round((intval($width)/16)*9);
+ }
+ else
+ {
+ $height = round((intval($width)/4)*3);
+ }
+ }
+ else
+ {
+ $height = 376;
+ }
+ }
+ elseif ($mime == 'audio')
+ {
+ $height = 0;
+ }
+
+ // Set proper placeholder value
+ if ($mime == 'audio')
+ {
+ $placeholder = $audio;
+ }
+ elseif ($mime == 'video')
+ {
+ $placeholder = $video;
+ }
+
+ $embed = '';
+
+ // Make sure the JS library is included
+ if (!$native)
+ {
+ static $javascript_outputted = null;
+ if (!$javascript_outputted && $this->javascript)
+ {
+ $embed .= '<script type="text/javascript" src="?' . htmlspecialchars($this->javascript) . '"></script>';
+ $javascript_outputted = true;
+ }
+ }
+
+ // Odeo Feed MP3's
+ if ($handler == 'odeo')
+ {
+ if ($native)
+ {
+ $embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://adobe.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
+ }
+ else
+ {
+ $embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
+ }
+ }
+
+ // Flash
+ elseif ($handler == 'flash')
+ {
+ if ($native)
+ {
+ $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
+ }
+ }
+
+ // Flash Media Player file types.
+ // Preferred handler for MP3 file types.
+ elseif ($handler == 'fmedia' || ($handler == 'mp3' && $mediaplayer != ''))
+ {
+ $height += 20;
+ if ($native)
+ {
+ $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
+ }
+ }
+
+ // QuickTime 7 file types. Need to test with QuickTime 6.
+ // Only handle MP3's if the Flash Media Player is not present.
+ elseif ($handler == 'quicktime' || ($handler == 'mp3' && $mediaplayer == ''))
+ {
+ $height += 16;
+ if ($native)
+ {
+ if ($placeholder != ""){
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ else {
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
+ }
+ }
+
+ // Windows Media
+ elseif ($handler == 'wmedia')
+ {
+ $height += 45;
+ if ($native)
+ {
+ $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
+ }
+ }
+
+ // Everything else
+ else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
+
+ return $embed;
+ }
+
+ function get_real_type($find_handler = false)
+ {
+ // If it's Odeo, let's get it out of the way.
+ if (substr(strtolower($this->get_link()), 0, 15) == 'http://odeo.com')
+ {
+ return 'odeo';
+ }
+
+ // Mime-types by handler.
+ $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
+ $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
+ $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
+ $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
+ $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
+
+ if ($this->get_type() !== null)
+ {
+ $type = strtolower($this->type);
+ }
+ else
+ {
+ $type = null;
+ }
+
+ // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
+ if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
+ {
+ switch (strtolower($this->get_extension()))
+ {
+ // Audio mime-types
+ case 'aac':
+ case 'adts':
+ $type = 'audio/acc';
+ break;
+
+ case 'aif':
+ case 'aifc':
+ case 'aiff':
+ case 'cdda':
+ $type = 'audio/aiff';
+ break;
+
+ case 'bwf':
+ $type = 'audio/wav';
+ break;
+
+ case 'kar':
+ case 'mid':
+ case 'midi':
+ case 'smf':
+ $type = 'audio/midi';
+ break;
+
+ case 'm4a':
+ $type = 'audio/x-m4a';
+ break;
+
+ case 'mp3':
+ case 'swa':
+ $type = 'audio/mp3';
+ break;
+
+ case 'wav':
+ $type = 'audio/wav';
+ break;
+
+ case 'wax':
+ $type = 'audio/x-ms-wax';
+ break;
+
+ case 'wma':
+ $type = 'audio/x-ms-wma';
+ break;
+
+ // Video mime-types
+ case '3gp':
+ case '3gpp':
+ $type = 'video/3gpp';
+ break;
+
+ case '3g2':
+ case '3gp2':
+ $type = 'video/3gpp2';
+ break;
+
+ case 'asf':
+ $type = 'video/x-ms-asf';
+ break;
+
+ case 'flv':
+ $type = 'video/x-flv';
+ break;
+
+ case 'm1a':
+ case 'm1s':
+ case 'm1v':
+ case 'm15':
+ case 'm75':
+ case 'mp2':
+ case 'mpa':
+ case 'mpeg':
+ case 'mpg':
+ case 'mpm':
+ case 'mpv':
+ $type = 'video/mpeg';
+ break;
+
+ case 'm4v':
+ $type = 'video/x-m4v';
+ break;
+
+ case 'mov':
+ case 'qt':
+ $type = 'video/quicktime';
+ break;
+
+ case 'mp4':
+ case 'mpg4':
+ $type = 'video/mp4';
+ break;
+
+ case 'sdv':
+ $type = 'video/sd-video';
+ break;
+
+ case 'wm':
+ $type = 'video/x-ms-wm';
+ break;
+
+ case 'wmv':
+ $type = 'video/x-ms-wmv';
+ break;
+
+ case 'wvx':
+ $type = 'video/x-ms-wvx';
+ break;
+
+ // Flash mime-types
+ case 'spl':
+ $type = 'application/futuresplash';
+ break;
+
+ case 'swf':
+ $type = 'application/x-shockwave-flash';
+ break;
+ }
+ }
+
+ if ($find_handler)
+ {
+ if (in_array($type, $types_flash))
+ {
+ return 'flash';
+ }
+ elseif (in_array($type, $types_fmedia))
+ {
+ return 'fmedia';
+ }
+ elseif (in_array($type, $types_quicktime))
+ {
+ return 'quicktime';
+ }
+ elseif (in_array($type, $types_wmedia))
+ {
+ return 'wmedia';
+ }
+ elseif (in_array($type, $types_mp3))
+ {
+ return 'mp3';
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return $type;
+ }
+ }
+}
+
+class SimplePie_Caption
+{
+ var $type;
+ var $lang;
+ var $startTime;
+ var $endTime;
+ var $text;
+
+ // Constructor, used to input the data
+ function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
+ {
+ $this->type = $type;
+ $this->lang = $lang;
+ $this->startTime = $startTime;
+ $this->endTime = $endTime;
+ $this->text = $text;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_endtime()
+ {
+ if ($this->endTime !== null)
+ {
+ return $this->endTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_starttime()
+ {
+ if ($this->startTime !== null)
+ {
+ return $this->startTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_text()
+ {
+ if ($this->text !== null)
+ {
+ return $this->text;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Credit
+{
+ var $role;
+ var $scheme;
+ var $name;
+
+ // Constructor, used to input the data
+ function SimplePie_Credit($role = null, $scheme = null, $name = null)
+ {
+ $this->role = $role;
+ $this->scheme = $scheme;
+ $this->name = $name;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_role()
+ {
+ if ($this->role !== null)
+ {
+ return $this->role;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Copyright
+{
+ var $url;
+ var $label;
+
+ // Constructor, used to input the data
+ function SimplePie_Copyright($url = null, $label = null)
+ {
+ $this->url = $url;
+ $this->label = $label;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_url()
+ {
+ if ($this->url !== null)
+ {
+ return $this->url;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_attribution()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Rating
+{
+ var $scheme;
+ var $value;
+
+ // Constructor, used to input the data
+ function SimplePie_Rating($scheme = null, $value = null)
+ {
+ $this->scheme = $scheme;
+ $this->value = $value;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+class SimplePie_Restriction
+{
+ var $relationship;
+ var $type;
+ var $value;
+
+ // Constructor, used to input the data
+ function SimplePie_Restriction($relationship = null, $type = null, $value = null)
+ {
+ $this->relationship = $relationship;
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ function get_relationship()
+ {
+ if ($this->relationship !== null)
+ {
+ return $this->relationship;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * @todo Move to properly supporting RFC2616 (HTTP/1.1)
+ */
+class SimplePie_File
+{
+ var $url;
+ var $useragent;
+ var $success = true;
+ var $headers = array();
+ var $body;
+ var $status_code;
+ var $redirects = 0;
+ var $error;
+ var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+
+ function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
+ {
+ if (class_exists('idna_convert'))
+ {
+ $idn =& new idna_convert;
+ $parsed = SimplePie_Misc::parse_url($url);
+ $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->url = $url;
+ $this->useragent = $useragent;
+ if (preg_match('/^http(s)?:\/\//i', $url))
+ {
+ if ($useragent === null)
+ {
+ $useragent = ini_get('user_agent');
+ $this->useragent = $useragent;
+ }
+ if (!is_array($headers))
+ {
+ $headers = array();
+ }
+ if (!$force_fsockopen && function_exists('curl_exec'))
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
+ $fp = curl_init();
+ $headers2 = array();
+ foreach ($headers as $key => $value)
+ {
+ $headers2[] = "$key: $value";
+ }
+ if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, '');
+ }
+ curl_setopt($fp, CURLOPT_URL, $url);
+ curl_setopt($fp, CURLOPT_HEADER, 1);
+ curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_REFERER, $url);
+ curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
+ curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
+ if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
+ {
+ curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
+ }
+
+ $this->headers = curl_exec($fp);
+ if (curl_errno($fp) == 23 || curl_errno($fp) == 61)
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, 'none');
+ $this->headers = curl_exec($fp);
+ }
+ if (curl_errno($fp))
+ {
+ $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
+ $this->success = false;
+ }
+ else
+ {
+ $info = curl_getinfo($fp);
+ curl_close($fp);
+ $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
+ $this->headers = array_pop($this->headers);
+ $parser =& new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
+ $url_parts = parse_url($url);
+ if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) == 'https')
+ {
+ $url_parts['host'] = "ssl://$url_parts[host]";
+ $url_parts['port'] = 443;
+ }
+ if (!isset($url_parts['port']))
+ {
+ $url_parts['port'] = 80;
+ }
+ $fp = @fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout);
+ if (!$fp)
+ {
+ $this->error = 'fsockopen error: ' . $errstr;
+ $this->success = false;
+ }
+ else
+ {
+ stream_set_timeout($fp, $timeout);
+ if (isset($url_parts['path']))
+ {
+ if (isset($url_parts['query']))
+ {
+ $get = "$url_parts[path]?$url_parts[query]";
+ }
+ else
+ {
+ $get = $url_parts['path'];
+ }
+ }
+ else
+ {
+ $get = '/';
+ }
+ $out = "GET $get HTTP/1.0\r\n";
+ $out .= "Host: $url_parts[host]\r\n";
+ $out .= "User-Agent: $useragent\r\n";
+ if (extension_loaded('zlib'))
+ {
+ $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
+ }
+
+ if (isset($url_parts['user']) && isset($url_parts['pass']))
+ {
+ $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
+ }
+ foreach ($headers as $key => $value)
+ {
+ $out .= "$key: $value\r\n";
+ }
+ $out .= "Connection: Close\r\n\r\n";
+ fwrite($fp, $out);
+
+ $info = stream_get_meta_data($fp);
+
+ $this->headers = '';
+ while (!$info['eof'] && !$info['timed_out'])
+ {
+ $this->headers .= fread($fp, 1160);
+ $info = stream_get_meta_data($fp);
+ }
+ if (!$info['timed_out'])
+ {
+ $parser =& new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ if (isset($this->headers['content-encoding']))
+ {
+ // Hey, we act dumb elsewhere, so let's do that here too
+ switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
+ {
+ case 'gzip':
+ case 'x-gzip':
+ $decoder = new SimplePie_gzdecode($this->body);
+ if (!$decoder->parse())
+ {
+ $this->error = 'Unable to decode HTTP "gzip" stream';
+ $this->success = false;
+ }
+ else
+ {
+ $this->body = $decoder->data;
+ }
+ break;
+
+ case 'deflate':
+ if (($body = gzuncompress($this->body)) === false)
+ {
+ if (($body = gzinflate($this->body)) === false)
+ {
+ $this->error = 'Unable to decode HTTP "deflate" stream';
+ $this->success = false;
+ }
+ }
+ $this->body = $body;
+ break;
+
+ default:
+ $this->error = 'Unknown content coding';
+ $this->success = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->error = 'fsocket timed out';
+ $this->success = false;
+ }
+ fclose($fp);
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
+ if (!$this->body = file_get_contents($url))
+ {
+ $this->error = 'file_get_contents could not read the file';
+ $this->success = false;
+ }
+ }
+ }
+}
+
+/**
+ * HTTP Response Parser
+ *
+ * @package SimplePie
+ */
+class SimplePie_HTTP_Parser
+{
+ /**
+ * HTTP Version
+ *
+ * @access public
+ * @var float
+ */
+ var $http_version = 0.0;
+
+ /**
+ * Status code
+ *
+ * @access public
+ * @var int
+ */
+ var $status_code = 0;
+
+ /**
+ * Reason phrase
+ *
+ * @access public
+ * @var string
+ */
+ var $reason = '';
+
+ /**
+ * Key/value pairs of the headers
+ *
+ * @access public
+ * @var array
+ */
+ var $headers = array();
+
+ /**
+ * Body of the response
+ *
+ * @access public
+ * @var string
+ */
+ var $body = '';
+
+ /**
+ * Current state of the state machine
+ *
+ * @access private
+ * @var string
+ */
+ var $state = 'http_version';
+
+ /**
+ * Input data
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @access private
+ * @var int
+ */
+ var $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ * @access private
+ */
+ var $position = 0;
+
+ /**
+ * Name of the hedaer currently being parsed
+ *
+ * @access private
+ * @var string
+ */
+ var $name = '';
+
+ /**
+ * Value of the hedaer currently being parsed
+ *
+ * @access private
+ * @var string
+ */
+ var $value = '';
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ function SimplePie_HTTP_Parser($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return bool true on success, false on failure
+ */
+ function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit' || $this->state === 'body')
+ {
+ return true;
+ }
+ else
+ {
+ $this->http_version = '';
+ $this->status_code = '';
+ $this->reason = '';
+ $this->headers = array();
+ $this->body = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @access private
+ * @return bool true if there is further data, false if not
+ */
+ function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * See if the next character is LWS
+ *
+ * @access private
+ * @return bool true if the next character is LWS, false if not
+ */
+ function is_linear_whitespace()
+ {
+ return (bool) ($this->data[$this->position] === "\x09"
+ || $this->data[$this->position] === "\x20"
+ || ($this->data[$this->position] === "\x0A"
+ && isset($this->data[$this->position + 1])
+ && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
+ }
+
+ /**
+ * Parse the HTTP version
+ *
+ * @access private
+ */
+ function http_version()
+ {
+ if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
+ {
+ $len = strspn($this->data, '0123456789.', 5);
+ $this->http_version = substr($this->data, 5, $len);
+ $this->position += 5 + $len;
+ if (substr_count($this->http_version, '.') <= 1)
+ {
+ $this->http_version = (float) $this->http_version;
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ $this->state = 'status';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the status code
+ *
+ * @access private
+ */
+ function status()
+ {
+ if ($len = strspn($this->data, '0123456789', $this->position))
+ {
+ $this->status_code = (int) substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'reason';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the reason phrase
+ *
+ * @access private
+ */
+ function reason()
+ {
+ $len = strcspn($this->data, "\x0A", $this->position);
+ $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
+ $this->position += $len + 1;
+ $this->state = 'new_line';
+ }
+
+ /**
+ * Deal with a new line, shifting data around as needed
+ *
+ * @access private
+ */
+ function new_line()
+ {
+ $this->value = trim($this->value, "\x0D\x20");
+ if ($this->name !== '' && $this->value !== '')
+ {
+ $this->name = strtolower($this->name);
+ if (isset($this->headers[$this->name]))
+ {
+ $this->headers[$this->name] .= ', ' . $this->value;
+ }
+ else
+ {
+ $this->headers[$this->name] = $this->value;
+ }
+ }
+ $this->name = '';
+ $this->value = '';
+ if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ $this->state = 'body';
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ $this->state = 'body';
+ }
+ else
+ {
+ $this->state = 'name';
+ }
+ }
+
+ /**
+ * Parse a header name
+ *
+ * @access private
+ */
+ function name()
+ {
+ $len = strcspn($this->data, "\x0A:", $this->position);
+ if (isset($this->data[$this->position + $len]))
+ {
+ if ($this->data[$this->position + $len] === "\x0A")
+ {
+ $this->position += $len;
+ $this->state = 'new_line';
+ }
+ else
+ {
+ $this->name = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ $this->state = 'value';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse LWS, replacing consecutive LWS characters with a single space
+ *
+ * @access private
+ */
+ function linear_whitespace()
+ {
+ do
+ {
+ if (substr($this->data, $this->position, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ }
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ } while ($this->has_data() && $this->is_linear_whitespace());
+ $this->value .= "\x20";
+ }
+
+ /**
+ * See what state to move to while within non-quoted header values
+ *
+ * @access private
+ */
+ function value()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ $this->position++;
+ $this->state = 'quote';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ default:
+ $this->state = 'value_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while outside quotes
+ *
+ * @access private
+ */
+ function value_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * See what state to move to while within quoted header values
+ *
+ * @access private
+ */
+ function quote()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ $this->position++;
+ $this->state = 'value';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ case '\\':
+ $this->position++;
+ $this->state = 'quote_escaped';
+ break;
+
+ default:
+ $this->state = 'quote_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while within quotes
+ *
+ * @access private
+ */
+ function quote_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * Parse an escaped character within quotes
+ *
+ * @access private
+ */
+ function quote_escaped()
+ {
+ $this->value .= $this->data[$this->position];
+ $this->position++;
+ $this->state = 'quote';
+ }
+
+ /**
+ * Parse the body
+ *
+ * @access private
+ */
+ function body()
+ {
+ $this->body = substr($this->data, $this->position);
+ $this->state = 'emit';
+ }
+}
+
+/**
+ * gzdecode
+ *
+ * @package SimplePie
+ */
+class SimplePie_gzdecode
+{
+ /**
+ * Compressed data
+ *
+ * @access private
+ * @see gzdecode::$data
+ */
+ var $compressed_data;
+
+ /**
+ * Size of compressed data
+ *
+ * @access private
+ */
+ var $compressed_size;
+
+ /**
+ * Minimum size of a valid gzip string
+ *
+ * @access private
+ */
+ var $min_compressed_size = 18;
+
+ /**
+ * Current position of pointer
+ *
+ * @access private
+ */
+ var $position = 0;
+
+ /**
+ * Flags (FLG)
+ *
+ * @access private
+ */
+ var $flags;
+
+ /**
+ * Uncompressed data
+ *
+ * @access public
+ * @see gzdecode::$compressed_data
+ */
+ var $data;
+
+ /**
+ * Modified time
+ *
+ * @access public
+ */
+ var $MTIME;
+
+ /**
+ * Extra Flags
+ *
+ * @access public
+ */
+ var $XFL;
+
+ /**
+ * Operating System
+ *
+ * @access public
+ */
+ var $OS;
+
+ /**
+ * Subfield ID 1
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI2
+ */
+ var $SI1;
+
+ /**
+ * Subfield ID 2
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI1
+ */
+ var $SI2;
+
+ /**
+ * Extra field content
+ *
+ * @access public
+ * @see gzdecode::$SI1
+ * @see gzdecode::$SI2
+ */
+ var $extra_field;
+
+ /**
+ * Original filename
+ *
+ * @access public
+ */
+ var $filename;
+
+ /**
+ * Human readable comment
+ *
+ * @access public
+ */
+ var $comment;
+
+ /**
+ * Don't allow anything to be set
+ *
+ * @access public
+ */
+ function __set($name, $value)
+ {
+ trigger_error("Cannot write property $name", E_USER_ERROR);
+ }
+
+ /**
+ * Set the compressed string and related properties
+ *
+ * @access public
+ */
+ function SimplePie_gzdecode($data)
+ {
+ $this->compressed_data = $data;
+ $this->compressed_size = strlen($data);
+ }
+
+ /**
+ * Decode the GZIP stream
+ *
+ * @access public
+ */
+ function parse()
+ {
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Check ID1, ID2, and CM
+ if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
+ {
+ return false;
+ }
+
+ // Get the FLG (FLaGs)
+ $this->flags = ord($this->compressed_data[3]);
+
+ // FLG bits above (1 << 4) are reserved
+ if ($this->flags > 0x1F)
+ {
+ return false;
+ }
+
+ // Advance the pointer after the above
+ $this->position += 4;
+
+ // MTIME
+ $mtime = substr($this->compressed_data, $this->position, 4);
+ // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
+ if (current(unpack('S', "\x00\x01")) === 1)
+ {
+ $mtime = strrev($mtime);
+ }
+ $this->MTIME = current(unpack('l', $mtime));
+ $this->position += 4;
+
+ // Get the XFL (eXtra FLags)
+ $this->XFL = ord($this->compressed_data[$this->position++]);
+
+ // Get the OS (Operating System)
+ $this->OS = ord($this->compressed_data[$this->position++]);
+
+ // Parse the FEXTRA
+ if ($this->flags & 4)
+ {
+ // Read subfield IDs
+ $this->SI1 = $this->compressed_data[$this->position++];
+ $this->SI2 = $this->compressed_data[$this->position++];
+
+ // SI2 set to zero is reserved for future use
+ if ($this->SI2 === "\x00")
+ {
+ return false;
+ }
+
+ // Get the length of the extra field
+ $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+ $position += 2;
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 4;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the extra field to the given data
+ $this->extra_field = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FNAME
+ if ($this->flags & 8)
+ {
+ // Get the length of the filename
+ $len = strspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original filename to the given string
+ $this->filename = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FCOMMENT
+ if ($this->flags & 16)
+ {
+ // Get the length of the comment
+ $len = strspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original comment to the given string
+ $this->comment = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FHCRC
+ if ($this->flags & 2)
+ {
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 2;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Read the CRC
+ $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+
+ // Check the CRC matches
+ if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
+ {
+ $this->position += 2;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Decompress the actual data
+ if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
+ {
+ return false;
+ }
+ else
+ {
+ $this->position = $this->compressed_size - 8;
+ }
+
+ // Check CRC of data
+ $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
+ {
+ return false;
+ }*/
+
+ // Check ISIZE of data
+ $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
+ {
+ return false;
+ }
+
+ // Wow, against all odds, we've actually got a valid gzip string
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+class SimplePie_Cache
+{
+ /**
+ * Don't call the constructor. Please.
+ *
+ * @access private
+ */
+ function SimplePie_Cache()
+ {
+ trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR);
+ }
+
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @static
+ * @access public
+ */
+ function create($location, $filename, $extension)
+ {
+ return new SimplePie_Cache_File($location, $filename, $extension);
+ }
+}
+
+class SimplePie_Cache_File
+{
+ var $location;
+ var $filename;
+ var $extension;
+ var $name;
+
+ function SimplePie_Cache_File($location, $filename, $extension)
+ {
+ $this->location = $location;
+ $this->filename = rawurlencode($filename);
+ $this->extension = rawurlencode($extension);
+ $this->name = "$location/$this->filename.$this->extension";
+ }
+
+ function save($data)
+ {
+ if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
+ {
+ if (is_a($data, 'SimplePie'))
+ {
+ $data = $data->data;
+ }
+
+ $data = serialize($data);
+
+ if (function_exists('file_put_contents'))
+ {
+ return (bool) file_put_contents($this->name, $data);
+ }
+ else
+ {
+ $fp = fopen($this->name, 'wb');
+ if ($fp)
+ {
+ fwrite($fp, $data);
+ fclose($fp);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ function load()
+ {
+ if (file_exists($this->name) && is_readable($this->name))
+ {
+ return unserialize(file_get_contents($this->name));
+ }
+ return false;
+ }
+
+ function mtime()
+ {
+ if (file_exists($this->name))
+ {
+ return filemtime($this->name);
+ }
+ return false;
+ }
+
+ function touch()
+ {
+ if (file_exists($this->name))
+ {
+ return touch($this->name);
+ }
+ return false;
+ }
+
+ function unlink()
+ {
+ if (file_exists($this->name))
+ {
+ return unlink($this->name);
+ }
+ return false;
+ }
+}
+
+class SimplePie_Misc
+{
+ function time_hms($seconds)
+ {
+ $time = '';
+
+ $hours = floor($seconds / 3600);
+ $remainder = $seconds % 3600;
+ if ($hours > 0)
+ {
+ $time .= $hours.':';
+ }
+
+ $minutes = floor($remainder / 60);
+ $seconds = $remainder % 60;
+ if ($minutes < 10 && $hours > 0)
+ {
+ $minutes = '0' . $minutes;
+ }
+ if ($seconds < 10)
+ {
+ $seconds = '0' . $seconds;
+ }
+
+ $time .= $minutes.':';
+ $time .= $seconds;
+
+ return $time;
+ }
+
+ function absolutize_url($relative, $base)
+ {
+ if ($relative !== '')
+ {
+ $relative = SimplePie_Misc::parse_url($relative);
+ if ($relative['scheme'] !== '')
+ {
+ $target = $relative;
+ }
+ elseif ($base !== '')
+ {
+ $base = SimplePie_Misc::parse_url($base);
+ $target = SimplePie_Misc::parse_url('');
+ if ($relative['authority'] !== '')
+ {
+ $target = $relative;
+ $target['scheme'] = $base['scheme'];
+ }
+ else
+ {
+ $target['scheme'] = $base['scheme'];
+ $target['authority'] = $base['authority'];
+ if ($relative['path'] !== '')
+ {
+ if (strpos($relative['path'], '/') === 0)
+ {
+ $target['path'] = $relative['path'];
+ }
+ elseif ($base['authority'] !== '' && $base['path'] === '')
+ {
+ $target['path'] = '/' . $relative['path'];
+ }
+ elseif (($last_segment = strrpos($base['path'], '/')) !== false)
+ {
+ $target['path'] = substr($base['path'], 0, $last_segment + 1) . $relative['path'];
+ }
+ else
+ {
+ $target['path'] = $relative['path'];
+ }
+ $target['query'] = $relative['query'];
+ }
+ else
+ {
+ $target['path'] = $base['path'];
+ if ($relative['query'] !== '')
+ {
+ $target['query'] = $relative['query'];
+ }
+ elseif ($base['query'] !== '')
+ {
+ $target['query'] = $base['query'];
+ }
+ }
+ }
+ $target['fragment'] = $relative['fragment'];
+ }
+ else
+ {
+ // No base URL, just return the relative URL
+ $target = $relative;
+ }
+ $return = SimplePie_Misc::compress_parse_url($target['scheme'], $target['authority'], $target['path'], $target['query'], $target['fragment']);
+ }
+ else
+ {
+ $return = $base;
+ }
+ $return = SimplePie_Misc::normalize_url($return);
+ return $return;
+ }
+
+ function remove_dot_segments($input)
+ {
+ $output = '';
+ while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input == '.' || $input == '..')
+ {
+ // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
+ if (strpos($input, '../') === 0)
+ {
+ $input = substr($input, 3);
+ }
+ elseif (strpos($input, './') === 0)
+ {
+ $input = substr($input, 2);
+ }
+ // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
+ elseif (strpos($input, '/./') === 0)
+ {
+ $input = substr_replace($input, '/', 0, 3);
+ }
+ elseif ($input == '/.')
+ {
+ $input = '/';
+ }
+ // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
+ elseif (strpos($input, '/../') === 0)
+ {
+ $input = substr_replace($input, '/', 0, 4);
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ elseif ($input == '/..')
+ {
+ $input = '/';
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
+ elseif ($input == '.' || $input == '..')
+ {
+ $input = '';
+ }
+ // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
+ elseif (($pos = strpos($input, '/', 1)) !== false)
+ {
+ $output .= substr($input, 0, $pos);
+ $input = substr_replace($input, '', 0, $pos);
+ }
+ else
+ {
+ $output .= $input;
+ $input = '';
+ }
+ }
+ return $output . $input;
+ }
+
+ function get_element($realname, $string)
+ {
+ $return = array();
+ $name = preg_quote($realname, '/');
+ if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+ {
+ for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
+ {
+ $return[$i]['tag'] = $realname;
+ $return[$i]['full'] = $matches[$i][0][0];
+ $return[$i]['offset'] = $matches[$i][0][1];
+ if (strlen($matches[$i][3][0]) <= 2)
+ {
+ $return[$i]['self_closing'] = true;
+ }
+ else
+ {
+ $return[$i]['self_closing'] = false;
+ $return[$i]['content'] = $matches[$i][4][0];
+ }
+ $return[$i]['attribs'] = array();
+ if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
+ {
+ for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
+ {
+ if (count($attribs[$j]) == 2)
+ {
+ $attribs[$j][2] = $attribs[$j][1];
+ }
+ $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
+ }
+ }
+ }
+ }
+ return $return;
+ }
+
+ function element_implode($element)
+ {
+ $full = "<$element[tag]";
+ foreach ($element['attribs'] as $key => $value)
+ {
+ $key = strtolower($key);
+ $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
+ }
+ if ($element['self_closing'])
+ {
+ $full .= ' />';
+ }
+ else
+ {
+ $full .= ">$element[content]</$element[tag]>";
+ }
+ return $full;
+ }
+
+ function error($message, $level, $file, $line)
+ {
+ switch ($level)
+ {
+ case E_USER_ERROR:
+ $note = 'PHP Error';
+ break;
+ case E_USER_WARNING:
+ $note = 'PHP Warning';
+ break;
+ case E_USER_NOTICE:
+ $note = 'PHP Notice';
+ break;
+ default:
+ $note = 'Unknown Error';
+ break;
+ }
+ error_log("$note: $message in $file on line $line", 0);
+ return $message;
+ }
+
+ /**
+ * If a file has been cached, retrieve and display it.
+ *
+ * This is most useful for caching images (get_favicon(), etc.),
+ * however it works for all cached files. This WILL NOT display ANY
+ * file/image/page/whatever, but rather only display what has already
+ * been cached by SimplePie.
+ *
+ * @access public
+ * @see SimplePie::get_favicon()
+ * @param str $identifier_url URL that is used to identify the content.
+ * This may or may not be the actual URL of the live content.
+ * @param str $cache_location Location of SimplePie's cache. Defaults
+ * to './cache'.
+ * @param str $cache_extension The file extension that the file was
+ * cached with. Defaults to 'spc'.
+ * @param str $cache_class Name of the cache-handling class being used
+ * in SimplePie. Defaults to 'SimplePie_Cache', and should be left
+ * as-is unless you've overloaded the class.
+ * @param str $cache_name_function Obsolete. Exists for backwards
+ * compatibility reasons only.
+ */
+ function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5')
+ {
+ $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension);
+
+ if ($file = $cache->load())
+ {
+ if (isset($file['headers']['content-type']))
+ {
+ header('Content-type:' . $file['headers']['content-type']);
+ }
+ else
+ {
+ header('Content-type: application/octet-stream');
+ }
+ header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
+ echo $file['body'];
+ exit;
+ }
+
+ die('Cached file for ' . $identifier_url . ' cannot be found.');
+ }
+
+ function fix_protocol($url, $http = 1)
+ {
+ $url = SimplePie_Misc::normalize_url($url);
+ $parsed = SimplePie_Misc::parse_url($url);
+ if ($parsed['scheme'] !== '' && $parsed['scheme'] != 'http' && $parsed['scheme'] != 'https')
+ {
+ return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
+ }
+
+ if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
+ {
+ return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
+ }
+
+ if ($http == 2 && $parsed['scheme'] !== '')
+ {
+ return "feed:$url";
+ }
+ elseif ($http == 3 && strtolower($parsed['scheme']) == 'http')
+ {
+ return substr_replace($url, 'podcast', 0, 4);
+ }
+ elseif ($http == 4 && strtolower($parsed['scheme']) == 'http')
+ {
+ return substr_replace($url, 'itpc', 0, 4);
+ }
+ else
+ {
+ return $url;
+ }
+ }
+
+ function parse_url($url)
+ {
+ static $cache = array();
+ if (isset($cache[$url]))
+ {
+ return $cache[$url];
+ }
+ elseif (preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $url, $match))
+ {
+ for ($i = count($match); $i <= 9; $i++)
+ {
+ $match[$i] = '';
+ }
+ return $cache[$url] = array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
+ }
+ else
+ {
+ return $cache[$url] = array('scheme' => '', 'authority' => '', 'path' => '', 'query' => '', 'fragment' => '');
+ }
+ }
+
+ function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
+ {
+ $return = '';
+ if ($scheme !== '')
+ {
+ $return .= "$scheme:";
+ }
+ if ($authority !== '')
+ {
+ $return .= "//$authority";
+ }
+ if ($path !== '')
+ {
+ $return .= $path;
+ }
+ if ($query !== '')
+ {
+ $return .= "?$query";
+ }
+ if ($fragment !== '')
+ {
+ $return .= "#$fragment";
+ }
+ return $return;
+ }
+
+ function normalize_url($url)
+ {
+ $url = preg_replace_callback('/%([0-9A-Fa-f]{2})/', array('SimplePie_Misc', 'percent_encoding_normalization'), $url);
+ $url = SimplePie_Misc::parse_url($url);
+ $url['scheme'] = strtolower($url['scheme']);
+ if ($url['authority'] !== '')
+ {
+ $url['authority'] = strtolower($url['authority']);
+ $url['path'] = SimplePie_Misc::remove_dot_segments($url['path']);
+ }
+ return SimplePie_Misc::compress_parse_url($url['scheme'], $url['authority'], $url['path'], $url['query'], $url['fragment']);
+ }
+
+ function percent_encoding_normalization($match)
+ {
+ $integer = hexdec($match[1]);
+ if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer == 0x2D || $integer == 0x2E || $integer == 0x5F || $integer == 0x7E)
+ {
+ return chr($integer);
+ }
+ else
+ {
+ return strtoupper($match[0]);
+ }
+ }
+
+ /**
+ * Remove bad UTF-8 bytes
+ *
+ * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C
+ * FAQ: Multilingual Forms (modified to include full ASCII range)
+ *
+ * @author Geoffrey Sneddon
+ * @see http://www.w3.org/International/questions/qa-forms-utf-8
+ * @param string $str String to remove bad UTF-8 bytes from
+ * @return string UTF-8 string
+ */
+ function utf8_bad_replace($str)
+ {
+ if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str)))
+ {
+ return $return;
+ }
+ elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8')))
+ {
+ return $return;
+ }
+ elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches))
+ {
+ return implode("\xEF\xBF\xBD", $matches[0]);
+ }
+ elseif ($str !== '')
+ {
+ return "\xEF\xBF\xBD";
+ }
+ else
+ {
+ return '';
+ }
+ }
+
+ /**
+ * Converts a Windows-1252 encoded string to a UTF-8 encoded string
+ *
+ * @static
+ * @access public
+ * @param string $string Windows-1252 encoded string
+ * @return string UTF-8 encoded string
+ */
+ function windows_1252_to_utf8($string)
+ {
+ static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
+
+ return strtr($string, $convert_table);
+ }
+
+ function change_encoding($data, $input, $output)
+ {
+ $input = SimplePie_Misc::encoding($input);
+ $output = SimplePie_Misc::encoding($output);
+
+ // We fail to fail on non US-ASCII bytes
+ if ($input === 'US-ASCII')
+ {
+ static $non_ascii_octects = '';
+ if (!$non_ascii_octects)
+ {
+ for ($i = 0x80; $i <= 0xFF; $i++)
+ {
+ $non_ascii_octects .= chr($i);
+ }
+ }
+ $data = substr($data, 0, strcspn($data, $non_ascii_octects));
+ }
+
+ // This is first, as behaviour of this is completely predictable
+ if ($input === 'Windows-1252' && $output === 'UTF-8')
+ {
+ return SimplePie_Misc::windows_1252_to_utf8($data);
+ }
+ // This is second, as behaviour of this varies only with PHP version
+ elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($data, $output, $input)))
+ {
+ return $return;
+ }
+ // This is last, as behaviour of this varies with OS userland and PHP version
+ elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data)))
+ {
+ return $return;
+ }
+ // If we can't do anything, just fail
+ else
+ {
+ return false;
+ }
+ }
+
+ function encoding($charset)
+ {
+ /* Character sets are case-insensitive, and also need some further
+ normalization in the real world (though we'll return them in the form given
+ in their registration). */
+ switch (strtolower(preg_replace('/[\x09-\x0D\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]/', '', $charset)))
+ {
+ case 'adobestandardencoding':
+ case 'csadobestandardencoding':
+ return 'Adobe-Standard-Encoding';
+
+ case 'adobesymbolencoding':
+ case 'cshppsmath':
+ return 'Adobe-Symbol-Encoding';
+
+ case 'ami1251':
+ case 'ami1251':
+ case 'amiga1251':
+ case 'amiga1251':
+ return 'Amiga-1251';
+
+ case 'ansix31101983':
+ case 'csat5001983':
+ case 'csiso99naplps':
+ case 'isoir99':
+ case 'naplps':
+ return 'ANSI_X3.110-1983';
+
+ case 'arabic7':
+ case 'asmo449':
+ case 'csiso89asmo449':
+ case 'isoir89':
+ case 'iso9036':
+ return 'ASMO_449';
+
+ case 'big5':
+ case 'csbig5':
+ case 'xxbig5':
+ return 'Big5';
+
+ case 'big5hkscs':
+ return 'Big5-HKSCS';
+
+ case 'bocu1':
+ case 'csbocu1':
+ return 'BOCU-1';
+
+ case 'brf':
+ case 'csbrf':
+ return 'BRF';
+
+ case 'bs4730':
+ case 'csiso4unitedkingdom':
+ case 'gb':
+ case 'isoir4':
+ case 'iso646gb':
+ case 'uk':
+ return 'BS_4730';
+
+ case 'bsviewdata':
+ case 'csiso47bsviewdata':
+ case 'isoir47':
+ return 'BS_viewdata';
+
+ case 'cesu8':
+ case 'cscesu8':
+ return 'CESU-8';
+
+ case 'ca':
+ case 'csa71':
+ case 'csaz243419851':
+ case 'csiso121canadian1':
+ case 'isoir121':
+ case 'iso646ca':
+ return 'CSA_Z243.4-1985-1';
+
+ case 'csa72':
+ case 'csaz243419852':
+ case 'csiso122canadian2':
+ case 'isoir122':
+ case 'iso646ca2':
+ return 'CSA_Z243.4-1985-2';
+
+ case 'csaz24341985gr':
+ case 'csiso123csaz24341985gr':
+ case 'isoir123':
+ return 'CSA_Z243.4-1985-gr';
+
+ case 'csiso139csn369103':
+ case 'csn369103':
+ case 'isoir139':
+ return 'CSN_369103';
+
+ case 'csdecmcs':
+ case 'dec':
+ case 'decmcs':
+ return 'DEC-MCS';
+
+ case 'csiso21german':
+ case 'de':
+ case 'din66003':
+ case 'isoir21':
+ case 'iso646de':
+ return 'DIN_66003';
+
+ case 'csdkus':
+ case 'dkus':
+ return 'dk-us';
+
+ case 'csiso646danish':
+ case 'dk':
+ case 'ds2089':
+ case 'ds2089':
+ case 'iso646dk':
+ return 'DS_2089';
+
+ case 'csibmebcdicatde':
+ case 'ebcdicatde':
+ return 'EBCDIC-AT-DE';
+
+ case 'csebcdicatdea':
+ case 'ebcdicatdea':
+ return 'EBCDIC-AT-DE-A';
+
+ case 'csebcdiccafr':
+ case 'ebcdiccafr':
+ return 'EBCDIC-CA-FR';
+
+ case 'csebcdicdkno':
+ case 'ebcdicdkno':
+ return 'EBCDIC-DK-NO';
+
+ case 'csebcdicdknoa':
+ case 'ebcdicdknoa':
+ return 'EBCDIC-DK-NO-A';
+
+ case 'csebcdices':
+ case 'ebcdices':
+ return 'EBCDIC-ES';
+
+ case 'csebcdicesa':
+ case 'ebcdicesa':
+ return 'EBCDIC-ES-A';
+
+ case 'csebcdicess':
+ case 'ebcdicess':
+ return 'EBCDIC-ES-S';
+
+ case 'csebcdicfise':
+ case 'ebcdicfise':
+ return 'EBCDIC-FI-SE';
+
+ case 'csebcdicfisea':
+ case 'ebcdicfisea':
+ return 'EBCDIC-FI-SE-A';
+
+ case 'csebcdicfr':
+ case 'ebcdicfr':
+ return 'EBCDIC-FR';
+
+ case 'csebcdicit':
+ case 'ebcdicit':
+ return 'EBCDIC-IT';
+
+ case 'csebcdicpt':
+ case 'ebcdicpt':
+ return 'EBCDIC-PT';
+
+ case 'csebcdicuk':
+ case 'ebcdicuk':
+ return 'EBCDIC-UK';
+
+ case 'csebcdicus':
+ case 'ebcdicus':
+ return 'EBCDIC-US';
+
+ case 'csiso111ecmacyrillic':
+ case 'ecmacyrillic':
+ case 'isoir111':
+ case 'koi8e':
+ return 'ECMA-cyrillic';
+
+ case 'csiso17spanish':
+ case 'es':
+ case 'isoir17':
+ case 'iso646es':
+ return 'ES';
+
+ case 'csiso85spanish2':
+ case 'es2':
+ case 'isoir85':
+ case 'iso646es2':
+ return 'ES2';
+
+ case 'cseucfixwidjapanese':
+ case 'extendedunixcodefixedwidthforjapanese':
+ return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
+
+ case 'cseucpkdfmtjapanese':
+ case 'eucjp':
+ case 'extendedunixcodepackedformatforjapanese':
+ return 'Extended_UNIX_Code_Packed_Format_for_Japanese';
+
+ case 'gb18030':
+ return 'GB18030';
+
+ case 'cp936':
+ case 'gbk':
+ case 'ms936':
+ case 'windows936':
+ case 'csgb2312':
+ case 'gb2312':
+ case 'chinese':
+ case 'csiso58gb231280':
+ case 'gb231280':
+ case 'isoir58':
+ return 'GBK';
+
+ case 'cn':
+ case 'csiso57gb1988':
+ case 'gb198880':
+ case 'isoir57':
+ case 'iso646cn':
+ return 'GB_1988-80';
+
+ case 'csiso153gost1976874':
+ case 'gost1976874':
+ case 'isoir153':
+ case 'stsev35888':
+ return 'GOST_19768-74';
+
+ case 'csiso150':
+ case 'csiso150greekccitt':
+ case 'greekccitt':
+ case 'isoir150':
+ return 'greek-ccitt';
+
+ case 'csiso88greek7':
+ case 'greek7':
+ case 'isoir88':
+ return 'greek7';
+
+ case 'csiso18greek7old':
+ case 'greek7old':
+ case 'isoir18':
+ return 'greek7-old';
+
+ case 'cshpdesktop':
+ case 'hpdesktop':
+ return 'HP-DeskTop';
+
+ case 'cshplegal':
+ case 'hplegal':
+ return 'HP-Legal';
+
+ case 'cshpmath8':
+ case 'hpmath8':
+ return 'HP-Math8';
+
+ case 'cshppifont':
+ case 'hppifont':
+ return 'HP-Pi-font';
+
+ case 'cshproman8':
+ case 'hproman8':
+ case 'r8':
+ case 'roman8':
+ return 'hp-roman8';
+
+ case 'hzgb2312':
+ return 'HZ-GB-2312';
+
+ case 'csibmsymbols':
+ case 'ibmsymbols':
+ return 'IBM-Symbols';
+
+ case 'csibmthai':
+ case 'ibmthai':
+ return 'IBM-Thai';
+
+ case 'ccsid00858':
+ case 'cp00858':
+ case 'ibm00858':
+ case 'pcmultilingual850euro':
+ return 'IBM00858';
+
+ case 'ccsid00924':
+ case 'cp00924':
+ case 'ebcdiclatin9euro':
+ case 'ibm00924':
+ return 'IBM00924';
+
+ case 'ccsid01140':
+ case 'cp01140':
+ case 'ebcdicus37euro':
+ case 'ibm01140':
+ return 'IBM01140';
+
+ case 'ccsid01141':
+ case 'cp01141':
+ case 'ebcdicde273euro':
+ case 'ibm01141':
+ return 'IBM01141';
+
+ case 'ccsid01142':
+ case 'cp01142':
+ case 'ebcdicdk277euro':
+ case 'ebcdicno277euro':
+ case 'ibm01142':
+ return 'IBM01142';
+
+ case 'ccsid01143':
+ case 'cp01143':
+ case 'ebcdicfi278euro':
+ case 'ebcdicse278euro':
+ case 'ibm01143':
+ return 'IBM01143';
+
+ case 'ccsid01144':
+ case 'cp01144':
+ case 'ebcdicit280euro':
+ case 'ibm01144':
+ return 'IBM01144';
+
+ case 'ccsid01145':
+ case 'cp01145':
+ case 'ebcdices284euro':
+ case 'ibm01145':
+ return 'IBM01145';
+
+ case 'ccsid01146':
+ case 'cp01146':
+ case 'ebcdicgb285euro':
+ case 'ibm01146':
+ return 'IBM01146';
+
+ case 'ccsid01147':
+ case 'cp01147':
+ case 'ebcdicfr297euro':
+ case 'ibm01147':
+ return 'IBM01147';
+
+ case 'ccsid01148':
+ case 'cp01148':
+ case 'ebcdicinternational500euro':
+ case 'ibm01148':
+ return 'IBM01148';
+
+ case 'ccsid01149':
+ case 'cp01149':
+ case 'ebcdicis871euro':
+ case 'ibm01149':
+ return 'IBM01149';
+
+ case 'cp037':
+ case 'csibm037':
+ case 'ebcdiccpca':
+ case 'ebcdiccpnl':
+ case 'ebcdiccpus':
+ case 'ebcdiccpwt':
+ case 'ibm037':
+ return 'IBM037';
+
+ case 'cp038':
+ case 'csibm038':
+ case 'ebcdicint':
+ case 'ibm038':
+ return 'IBM038';
+
+ case 'cp273':
+ case 'csibm273':
+ case 'ibm273':
+ return 'IBM273';
+
+ case 'cp274':
+ case 'csibm274':
+ case 'ebcdicbe':
+ case 'ibm274':
+ return 'IBM274';
+
+ case 'cp275':
+ case 'csibm275':
+ case 'ebcdicbr':
+ case 'ibm275':
+ return 'IBM275';
+
+ case 'csibm277':
+ case 'ebcdiccpdk':
+ case 'ebcdiccpno':
+ case 'ibm277':
+ return 'IBM277';
+
+ case 'cp278':
+ case 'csibm278':
+ case 'ebcdiccpfi':
+ case 'ebcdiccpse':
+ case 'ibm278':
+ return 'IBM278';
+
+ case 'cp280':
+ case 'csibm280':
+ case 'ebcdiccpit':
+ case 'ibm280':
+ return 'IBM280';
+
+ case 'cp281':
+ case 'csibm281':
+ case 'ebcdicjpe':
+ case 'ibm281':
+ return 'IBM281';
+
+ case 'cp284':
+ case 'csibm284':
+ case 'ebcdiccpes':
+ case 'ibm284':
+ return 'IBM284';
+
+ case 'cp285':
+ case 'csibm285':
+ case 'ebcdiccpgb':
+ case 'ibm285':
+ return 'IBM285';
+
+ case 'cp290':
+ case 'csibm290':
+ case 'ebcdicjpkana':
+ case 'ibm290':
+ return 'IBM290';
+
+ case 'cp297':
+ case 'csibm297':
+ case 'ebcdiccpfr':
+ case 'ibm297':
+ return 'IBM297';
+
+ case 'cp420':
+ case 'csibm420':
+ case 'ebcdiccpar1':
+ case 'ibm420':
+ return 'IBM420';
+
+ case 'cp423':
+ case 'csibm423':
+ case 'ebcdiccpgr':
+ case 'ibm423':
+ return 'IBM423';
+
+ case 'cp424':
+ case 'csibm424':
+ case 'ebcdiccphe':
+ case 'ibm424':
+ return 'IBM424';
+
+ case '437':
+ case 'cp437':
+ case 'cspc8codepage437':
+ case 'ibm437':
+ return 'IBM437';
+
+ case 'cp500':
+ case 'csibm500':
+ case 'ebcdiccpbe':
+ case 'ebcdiccpch':
+ case 'ibm500':
+ return 'IBM500';
+
+ case 'cp775':
+ case 'cspc775baltic':
+ case 'ibm775':
+ return 'IBM775';
+
+ case '850':
+ case 'cp850':
+ case 'cspc850multilingual':
+ case 'ibm850':
+ return 'IBM850';
+
+ case '851':
+ case 'cp851':
+ case 'csibm851':
+ case 'ibm851':
+ return 'IBM851';
+
+ case '852':
+ case 'cp852':
+ case 'cspcp852':
+ case 'ibm852':
+ return 'IBM852';
+
+ case '855':
+ case 'cp855':
+ case 'csibm855':
+ case 'ibm855':
+ return 'IBM855';
+
+ case '857':
+ case 'cp857':
+ case 'csibm857':
+ case 'ibm857':
+ return 'IBM857';
+
+ case '860':
+ case 'cp860':
+ case 'csibm860':
+ case 'ibm860':
+ return 'IBM860';
+
+ case '861':
+ case 'cpis':
+ case 'cp861':
+ case 'csibm861':
+ case 'ibm861':
+ return 'IBM861';
+
+ case '862':
+ case 'cp862':
+ case 'cspc862latinhebrew':
+ case 'ibm862':
+ return 'IBM862';
+
+ case '863':
+ case 'cp863':
+ case 'csibm863':
+ case 'ibm863':
+ return 'IBM863';
+
+ case 'cp864':
+ case 'csibm864':
+ case 'ibm864':
+ return 'IBM864';
+
+ case '865':
+ case 'cp865':
+ case 'csibm865':
+ case 'ibm865':
+ return 'IBM865';
+
+ case '866':
+ case 'cp866':
+ case 'csibm866':
+ case 'ibm866':
+ return 'IBM866';
+
+ case 'cpar':
+ case 'cp868':
+ case 'csibm868':
+ case 'ibm868':
+ return 'IBM868';
+
+ case '869':
+ case 'cpgr':
+ case 'cp869':
+ case 'csibm869':
+ case 'ibm869':
+ return 'IBM869';
+
+ case 'cp870':
+ case 'csibm870':
+ case 'ebcdiccproece':
+ case 'ebcdiccpyu':
+ case 'ibm870':
+ return 'IBM870';
+
+ case 'cp871':
+ case 'csibm871':
+ case 'ebcdiccpis':
+ case 'ibm871':
+ return 'IBM871';
+
+ case 'cp880':
+ case 'csibm880':
+ case 'ebcdiccyrillic':
+ case 'ibm880':
+ return 'IBM880';
+
+ case 'cp891':
+ case 'csibm891':
+ case 'ibm891':
+ return 'IBM891';
+
+ case 'cp903':
+ case 'csibm903':
+ case 'ibm903':
+ return 'IBM903';
+
+ case '904':
+ case 'cp904':
+ case 'csibbm904':
+ case 'ibm904':
+ return 'IBM904';
+
+ case 'cp905':
+ case 'csibm905':
+ case 'ebcdiccptr':
+ case 'ibm905':
+ return 'IBM905';
+
+ case 'cp918':
+ case 'csibm918':
+ case 'ebcdiccpar2':
+ case 'ibm918':
+ return 'IBM918';
+
+ case 'cp1026':
+ case 'csibm1026':
+ case 'ibm1026':
+ return 'IBM1026';
+
+ case 'ibm1047':
+ case 'ibm1047':
+ return 'IBM1047';
+
+ case 'csiso143iecp271':
+ case 'iecp271':
+ case 'isoir143':
+ return 'IEC_P27-1';
+
+ case 'csiso49inis':
+ case 'inis':
+ case 'isoir49':
+ return 'INIS';
+
+ case 'csiso50inis8':
+ case 'inis8':
+ case 'isoir50':
+ return 'INIS-8';
+
+ case 'csiso51iniscyrillic':
+ case 'iniscyrillic':
+ case 'isoir51':
+ return 'INIS-cyrillic';
+
+ case 'csinvariant':
+ case 'invariant':
+ return 'INVARIANT';
+
+ case 'iso2022cn':
+ return 'ISO-2022-CN';
+
+ case 'iso2022cnext':
+ return 'ISO-2022-CN-EXT';
+
+ case 'csiso2022jp':
+ case 'iso2022jp':
+ return 'ISO-2022-JP';
+
+ case 'csiso2022jp2':
+ case 'iso2022jp2':
+ return 'ISO-2022-JP-2';
+
+ case 'csiso2022kr':
+ case 'iso2022kr':
+ return 'ISO-2022-KR';
+
+ case 'cswindows30latin1':
+ case 'iso88591windows30latin1':
+ return 'ISO-8859-1-Windows-3.0-Latin-1';
+
+ case 'cswindows31latin1':
+ case 'iso88591windows31latin1':
+ return 'ISO-8859-1-Windows-3.1-Latin-1';
+
+ case 'csisolatin2':
+ case 'iso88592':
+ case 'isoir101':
+ case 'iso88592':
+ case 'iso885921987':
+ case 'l2':
+ case 'latin2':
+ return 'ISO-8859-2';
+
+ case 'cswindows31latin2':
+ case 'iso88592windowslatin2':
+ return 'ISO-8859-2-Windows-Latin-2';
+
+ case 'csisolatin3':
+ case 'iso88593':
+ case 'isoir109':
+ case 'iso88593':
+ case 'iso885931988':
+ case 'l3':
+ case 'latin3':
+ return 'ISO-8859-3';
+
+ case 'csisolatin4':
+ case 'iso88594':
+ case 'isoir110':
+ case 'iso88594':
+ case 'iso885941988':
+ case 'l4':
+ case 'latin4':
+ return 'ISO-8859-4';
+
+ case 'csisolatincyrillic':
+ case 'cyrillic':
+ case 'iso88595':
+ case 'isoir144':
+ case 'iso88595':
+ case 'iso885951988':
+ return 'ISO-8859-5';
+
+ case 'arabic':
+ case 'asmo708':
+ case 'csisolatinarabic':
+ case 'ecma114':
+ case 'iso88596':
+ case 'isoir127':
+ case 'iso88596':
+ case 'iso885961987':
+ return 'ISO-8859-6';
+
+ case 'csiso88596e':
+ case 'iso88596e':
+ case 'iso88596e':
+ return 'ISO-8859-6-E';
+
+ case 'csiso88596i':
+ case 'iso88596i':
+ case 'iso88596i':
+ return 'ISO-8859-6-I';
+
+ case 'csisolatingreek':
+ case 'ecma118':
+ case 'elot928':
+ case 'greek':
+ case 'greek8':
+ case 'iso88597':
+ case 'isoir126':
+ case 'iso88597':
+ case 'iso885971987':
+ return 'ISO-8859-7';
+
+ case 'csisolatinhebrew':
+ case 'hebrew':
+ case 'iso88598':
+ case 'isoir138':
+ case 'iso88598':
+ case 'iso885981988':
+ return 'ISO-8859-8';
+
+ case 'csiso88598e':
+ case 'iso88598e':
+ case 'iso88598e':
+ return 'ISO-8859-8-E';
+
+ case 'csiso88598i':
+ case 'iso88598i':
+ case 'iso88598i':
+ return 'ISO-8859-8-I';
+
+ case 'cswindows31latin5':
+ case 'iso88599windowslatin5':
+ return 'ISO-8859-9-Windows-Latin-5';
+
+ case 'csisolatin6':
+ case 'iso885910':
+ case 'isoir157':
+ case 'iso8859101992':
+ case 'l6':
+ case 'latin6':
+ return 'ISO-8859-10';
+
+ case 'iso885913':
+ return 'ISO-8859-13';
+
+ case 'iso885914':
+ case 'isoceltic':
+ case 'isoir199':
+ case 'iso885914':
+ case 'iso8859141998':
+ case 'l8':
+ case 'latin8':
+ return 'ISO-8859-14';
+
+ case 'iso885915':
+ case 'iso885915':
+ case 'latin9':
+ return 'ISO-8859-15';
+
+ case 'iso885916':
+ case 'isoir226':
+ case 'iso885916':
+ case 'iso8859162001':
+ case 'l10':
+ case 'latin10':
+ return 'ISO-8859-16';
+
+ case 'iso10646j1':
+ return 'ISO-10646-J-1';
+
+ case 'csunicode':
+ case 'iso10646ucs2':
+ return 'ISO-10646-UCS-2';
+
+ case 'csucs4':
+ case 'iso10646ucs4':
+ return 'ISO-10646-UCS-4';
+
+ case 'csunicodeascii':
+ case 'iso10646ucsbasic':
+ return 'ISO-10646-UCS-Basic';
+
+ case 'csunicodelatin1':
+ case 'iso10646':
+ case 'iso10646unicodelatin1':
+ return 'ISO-10646-Unicode-Latin1';
+
+ case 'csiso10646utf1':
+ case 'iso10646utf1':
+ return 'ISO-10646-UTF-1';
+
+ case 'csiso115481':
+ case 'iso115481':
+ case 'iso115481':
+ case 'isotr115481':
+ return 'ISO-11548-1';
+
+ case 'csiso90':
+ case 'isoir90':
+ return 'iso-ir-90';
+
+ case 'csunicodeibm1261':
+ case 'isounicodeibm1261':
+ return 'ISO-Unicode-IBM-1261';
+
+ case 'csunicodeibm1264':
+ case 'isounicodeibm1264':
+ return 'ISO-Unicode-IBM-1264';
+
+ case 'csunicodeibm1265':
+ case 'isounicodeibm1265':
+ return 'ISO-Unicode-IBM-1265';
+
+ case 'csunicodeibm1268':
+ case 'isounicodeibm1268':
+ return 'ISO-Unicode-IBM-1268';
+
+ case 'csunicodeibm1276':
+ case 'isounicodeibm1276':
+ return 'ISO-Unicode-IBM-1276';
+
+ case 'csiso646basic1983':
+ case 'iso646basic1983':
+ case 'ref':
+ return 'ISO_646.basic:1983';
+
+ case 'csiso2intlrefversion':
+ case 'irv':
+ case 'isoir2':
+ case 'iso646irv1983':
+ return 'ISO_646.irv:1983';
+
+ case 'csiso2033':
+ case 'e13b':
+ case 'isoir98':
+ case 'iso20331983':
+ return 'ISO_2033-1983';
+
+ case 'csiso5427cyrillic':
+ case 'isoir37':
+ case 'iso5427':
+ return 'ISO_5427';
+
+ case 'isoir54':
+ case 'iso5427cyrillic1981':
+ case 'iso54271981':
+ return 'ISO_5427:1981';
+
+ case 'csiso5428greek':
+ case 'isoir55':
+ case 'iso54281980':
+ return 'ISO_5428:1980';
+
+ case 'csiso6937add':
+ case 'isoir152':
+ case 'iso6937225':
+ return 'ISO_6937-2-25';
+
+ case 'csisotextcomm':
+ case 'isoir142':
+ case 'iso69372add':
+ return 'ISO_6937-2-add';
+
+ case 'csiso8859supp':
+ case 'isoir154':
+ case 'iso8859supp':
+ case 'latin125':
+ return 'ISO_8859-supp';
+
+ case 'csiso10367box':
+ case 'isoir155':
+ case 'iso10367box':
+ return 'ISO_10367-box';
+
+ case 'csiso15italian':
+ case 'isoir15':
+ case 'iso646it':
+ case 'it':
+ return 'IT';
+
+ case 'csiso13jisc6220jp':
+ case 'isoir13':
+ case 'jisc62201969':
+ case 'jisc62201969jp':
+ case 'katakana':
+ case 'x02017':
+ return 'JIS_C6220-1969-jp';
+
+ case 'csiso14jisc6220ro':
+ case 'isoir14':
+ case 'iso646jp':
+ case 'jisc62201969ro':
+ case 'jp':
+ return 'JIS_C6220-1969-ro';
+
+ case 'csiso42jisc62261978':
+ case 'isoir42':
+ case 'jisc62261978':
+ return 'JIS_C6226-1978';
+
+ case 'csiso87jisx0208':
+ case 'isoir87':
+ case 'jisc62261983':
+ case 'jisx02081983':
+ case 'x0208':
+ return 'JIS_C6226-1983';
+
+ case 'csiso91jisc62291984a':
+ case 'isoir91':
+ case 'jisc62291984a':
+ case 'jpocra':
+ return 'JIS_C6229-1984-a';
+
+ case 'csiso92jisc62991984b':
+ case 'isoir92':
+ case 'iso646jpocrb':
+ case 'jisc62291984b':
+ case 'jpocrb':
+ return 'JIS_C6229-1984-b';
+
+ case 'csiso93jis62291984badd':
+ case 'isoir93':
+ case 'jisc62291984badd':
+ case 'jpocrbadd':
+ return 'JIS_C6229-1984-b-add';
+
+ case 'csiso94jis62291984hand':
+ case 'isoir94':
+ case 'jisc62291984hand':
+ case 'jpocrhand':
+ return 'JIS_C6229-1984-hand';
+
+ case 'csiso95jis62291984handadd':
+ case 'isoir95':
+ case 'jisc62291984handadd':
+ case 'jpocrhandadd':
+ return 'JIS_C6229-1984-hand-add';
+
+ case 'csiso96jisc62291984kana':
+ case 'isoir96':
+ case 'jisc62291984kana':
+ return 'JIS_C6229-1984-kana';
+
+ case 'csjisencoding':
+ case 'jisencoding':
+ return 'JIS_Encoding';
+
+ case 'cshalfwidthkatakana':
+ case 'jisx0201':
+ case 'x0201':
+ return 'JIS_X0201';
+
+ case 'csiso159jisx02121990':
+ case 'isoir159':
+ case 'jisx02121990':
+ case 'x0212':
+ return 'JIS_X0212-1990';
+
+ case 'csiso141jusib1002':
+ case 'isoir141':
+ case 'iso646yu':
+ case 'js':
+ case 'jusib1002':
+ case 'yu':
+ return 'JUS_I.B1.002';
+
+ case 'csiso147macedonian':
+ case 'isoir147':
+ case 'jusib1003mac':
+ case 'macedonian':
+ return 'JUS_I.B1.003-mac';
+
+ case 'csiso146serbian':
+ case 'isoir146':
+ case 'jusib1003serb':
+ case 'serbian':
+ return 'JUS_I.B1.003-serb';
+
+ case 'koi7switched':
+ return 'KOI7-switched';
+
+ case 'cskoi8r':
+ case 'koi8r':
+ return 'KOI8-R';
+
+ case 'koi8u':
+ return 'KOI8-U';
+
+ case 'csksc5636':
+ case 'iso646kr':
+ case 'ksc5636':
+ return 'KSC5636';
+
+ case 'cskz1048':
+ case 'kz1048':
+ case 'rk1048':
+ case 'strk10482002':
+ return 'KZ-1048';
+
+ case 'csiso19latingreek':
+ case 'isoir19':
+ case 'latingreek':
+ return 'latin-greek';
+
+ case 'csiso27latingreek1':
+ case 'isoir27':
+ case 'latingreek1':
+ return 'Latin-greek-1';
+
+ case 'csiso158lap':
+ case 'isoir158':
+ case 'lap':
+ case 'latinlap':
+ return 'latin-lap';
+
+ case 'csmacintosh':
+ case 'mac':
+ case 'macintosh':
+ return 'macintosh';
+
+ case 'csmicrosoftpublishing':
+ case 'microsoftpublishing':
+ return 'Microsoft-Publishing';
+
+ case 'csmnem':
+ case 'mnem':
+ return 'MNEM';
+
+ case 'csmnemonic':
+ case 'mnemonic':
+ return 'MNEMONIC';
+
+ case 'csiso86hungarian':
+ case 'hu':
+ case 'isoir86':
+ case 'iso646hu':
+ case 'msz77953':
+ return 'MSZ_7795.3';
+
+ case 'csnatsdano':
+ case 'isoir91':
+ case 'natsdano':
+ return 'NATS-DANO';
+
+ case 'csnatsdanoadd':
+ case 'isoir92':
+ case 'natsdanoadd':
+ return 'NATS-DANO-ADD';
+
+ case 'csnatssefi':
+ case 'isoir81':
+ case 'natssefi':
+ return 'NATS-SEFI';
+
+ case 'csnatssefiadd':
+ case 'isoir82':
+ case 'natssefiadd':
+ return 'NATS-SEFI-ADD';
+
+ case 'csiso151cuba':
+ case 'cuba':
+ case 'isoir151':
+ case 'iso646cu':
+ case 'ncnc001081':
+ return 'NC_NC00-10:81';
+
+ case 'csiso69french':
+ case 'fr':
+ case 'isoir69':
+ case 'iso646fr':
+ case 'nfz62010':
+ return 'NF_Z_62-010';
+
+ case 'csiso25french':
+ case 'isoir25':
+ case 'iso646fr1':
+ case 'nfz620101973':
+ return 'NF_Z_62-010_(1973)';
+
+ case 'csiso60danishnorwegian':
+ case 'csiso60norwegian1':
+ case 'isoir60':
+ case 'iso646no':
+ case 'no':
+ case 'ns45511':
+ return 'NS_4551-1';
+
+ case 'csiso61norwegian2':
+ case 'isoir61':
+ case 'iso646no2':
+ case 'no2':
+ case 'ns45512':
+ return 'NS_4551-2';
+
+ case 'osdebcdicdf03irv':
+ return 'OSD_EBCDIC_DF03_IRV';
+
+ case 'osdebcdicdf041':
+ return 'OSD_EBCDIC_DF04_1';
+
+ case 'osdebcdicdf0415':
+ return 'OSD_EBCDIC_DF04_15';
+
+ case 'cspc8danishnorwegian':
+ case 'pc8danishnorwegian':
+ return 'PC8-Danish-Norwegian';
+
+ case 'cspc8turkish':
+ case 'pc8turkish':
+ return 'PC8-Turkish';
+
+ case 'csiso16portuguese':
+ case 'isoir16':
+ case 'iso646pt':
+ case 'pt':
+ return 'PT';
+
+ case 'csiso84portuguese2':
+ case 'isoir84':
+ case 'iso646pt2':
+ case 'pt2':
+ return 'PT2';
+
+ case 'cp154':
+ case 'csptcp154':
+ case 'cyrillicasian':
+ case 'pt154':
+ case 'ptcp154':
+ return 'PTCP154';
+
+ case 'scsu':
+ return 'SCSU';
+
+ case 'csiso10swedish':
+ case 'fi':
+ case 'isoir10':
+ case 'iso646fi':
+ case 'iso646se':
+ case 'se':
+ case 'sen850200b':
+ return 'SEN_850200_B';
+
+ case 'csiso11swedishfornames':
+ case 'isoir11':
+ case 'iso646se2':
+ case 'se2':
+ case 'sen850200c':
+ return 'SEN_850200_C';
+
+ case 'csshiftjis':
+ case 'mskanji':
+ case 'shiftjis':
+ return 'Shift_JIS';
+
+ case 'csiso102t617bit':
+ case 'isoir102':
+ case 't617bit':
+ return 'T.61-7bit';
+
+ case 'csiso103t618bit':
+ case 'isoir103':
+ case 't61':
+ case 't618bit':
+ return 'T.61-8bit';
+
+ case 'csiso128t101g2':
+ case 'isoir128':
+ case 't101g2':
+ return 'T.101-G2';
+
+ case 'cstscii':
+ case 'tscii':
+ return 'TSCII';
+
+ case 'csunicode11':
+ case 'unicode11':
+ return 'UNICODE-1-1';
+
+ case 'csunicode11utf7':
+ case 'unicode11utf7':
+ return 'UNICODE-1-1-UTF-7';
+
+ case 'csunknown8bit':
+ case 'unknown8bit':
+ return 'UNKNOWN-8BIT';
+
+ case 'ansix341968':
+ case 'ansix341986':
+ case 'ascii':
+ case 'cp367':
+ case 'csascii':
+ case 'ibm367':
+ case 'isoir6':
+ case 'iso646us':
+ case 'iso646irv1991':
+ case 'us':
+ case 'usascii':
+ return 'US-ASCII';
+
+ case 'csusdk':
+ case 'usdk':
+ return 'us-dk';
+
+ case 'utf7':
+ return 'UTF-7';
+
+ case 'utf8':
+ return 'UTF-8';
+
+ case 'utf16':
+ return 'UTF-16';
+
+ case 'utf16be':
+ return 'UTF-16BE';
+
+ case 'utf16le':
+ return 'UTF-16LE';
+
+ case 'utf32':
+ return 'UTF-32';
+
+ case 'utf32be':
+ return 'UTF-32BE';
+
+ case 'utf32le':
+ return 'UTF-32LE';
+
+ case 'csventurainternational':
+ case 'venturainternational':
+ return 'Ventura-International';
+
+ case 'csventuramath':
+ case 'venturamath':
+ return 'Ventura-Math';
+
+ case 'csventuraus':
+ case 'venturaus':
+ return 'Ventura-US';
+
+ case 'csiso70videotexsupp1':
+ case 'isoir70':
+ case 'videotexsuppl':
+ return 'videotex-suppl';
+
+ case 'csviqr':
+ case 'viqr':
+ return 'VIQR';
+
+ case 'csviscii':
+ case 'viscii':
+ return 'VISCII';
+
+ case 'cswindows31j':
+ case 'windows31j':
+ return 'Windows-31J';
+
+ case 'iso885911':
+ case 'tis620':
+ return 'Windows-874';
+
+ case 'cseuckr':
+ case 'euckr':
+ case 'windows949':
+ case 'csksc56011987':
+ case 'isoir149':
+ case 'korean':
+ case 'ksc5601':
+ case 'ksc56011987':
+ case 'ksc56011989':
+ return 'Windows-949';
+
+ case 'windows1250':
+ return 'windows-1250';
+
+ case 'windows1251':
+ return 'windows-1251';
+
+ case 'cp819':
+ case 'csisolatin1':
+ case 'ibm819':
+ case 'iso88591':
+ case 'isoir100':
+ case 'iso885911987':
+ case 'l1':
+ case 'latin1':
+ case 'windows1252':
+ return 'Windows-1252';
+
+ case 'windows1252':
+ return 'windows-1252';
+
+ case 'windows1253':
+ return 'windows-1253';
+
+ case 'csisolatin5':
+ case 'iso88599':
+ case 'isoir148':
+ case 'iso885991989':
+ case 'l5':
+ case 'latin5':
+ case 'windows1254':
+ return 'Windows-1254';
+
+ case 'windows1254':
+ return 'windows-1254';
+
+ case 'windows1255':
+ return 'windows-1255';
+
+ case 'windows1256':
+ return 'windows-1256';
+
+ case 'windows1257':
+ return 'windows-1257';
+
+ case 'windows1258':
+ return 'windows-1258';
+
+ default:
+ return $charset;
+ }
+ }
+
+ function get_curl_version()
+ {
+ if (is_array($curl = curl_version()))
+ {
+ $curl = $curl['version'];
+ }
+ elseif (substr($curl, 0, 5) == 'curl/')
+ {
+ $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
+ }
+ elseif (substr($curl, 0, 8) == 'libcurl/')
+ {
+ $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
+ }
+ else
+ {
+ $curl = 0;
+ }
+ return $curl;
+ }
+
+ function is_subclass_of($class1, $class2)
+ {
+ if (func_num_args() != 2)
+ {
+ trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
+ }
+ elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
+ {
+ return is_subclass_of($class1, $class2);
+ }
+ elseif (is_string($class1) && is_string($class2))
+ {
+ if (class_exists($class1))
+ {
+ if (class_exists($class2))
+ {
+ $class2 = strtolower($class2);
+ while ($class1 = strtolower(get_parent_class($class1)))
+ {
+ if ($class1 == $class2)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Strip HTML comments
+ *
+ * @access public
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ function strip_comments($data)
+ {
+ $output = '';
+ while (($start = strpos($data, '<!--')) !== false)
+ {
+ $output .= substr($data, 0, $start);
+ if (($end = strpos($data, '-->', $start)) !== false)
+ {
+ $data = substr_replace($data, '', 0, $end + 3);
+ }
+ else
+ {
+ $data = '';
+ }
+ }
+ return $output . $data;
+ }
+
+ function parse_date($dt)
+ {
+ $parser = SimplePie_Parse_Date::get();
+ return $parser->parse($dt);
+ }
+
+ /**
+ * Decode HTML entities
+ *
+ * @static
+ * @access public
+ * @param string $data Input data
+ * @return string Output data
+ */
+ function entities_decode($data)
+ {
+ $decoder = new SimplePie_Decode_HTML_Entities($data);
+ return $decoder->parse();
+ }
+
+ /**
+ * Remove RFC822 comments
+ *
+ * @access public
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ function uncomment_rfc822($string)
+ {
+ $string = (string) $string;
+ $position = 0;
+ $length = strlen($string);
+ $depth = 0;
+
+ $output = '';
+
+ while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+ {
+ $output .= substr($string, $position, $pos - $position);
+ $position = $pos + 1;
+ if ($string[$pos - 1] !== '\\')
+ {
+ $depth++;
+ while ($depth && $position < $length)
+ {
+ $position += strcspn($string, '()', $position);
+ if ($string[$position - 1] === '\\')
+ {
+ $position++;
+ continue;
+ }
+ elseif (isset($string[$position]))
+ {
+ switch ($string[$position])
+ {
+ case '(':
+ $depth++;
+ break;
+
+ case ')':
+ $depth--;
+ break;
+ }
+ $position++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ $output .= '(';
+ }
+ }
+ $output .= substr($string, $position);
+
+ return $output;
+ }
+
+ function parse_mime($mime)
+ {
+ if (($pos = strpos($mime, ';')) === false)
+ {
+ return trim($mime);
+ }
+ else
+ {
+ return trim(substr($mime, 0, $pos));
+ }
+ }
+
+ function htmlspecialchars_decode($string, $quote_style)
+ {
+ if (function_exists('htmlspecialchars_decode'))
+ {
+ return htmlspecialchars_decode($string, $quote_style);
+ }
+ else
+ {
+ return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
+ }
+ }
+
+ function atom_03_construct_type($attribs)
+ {
+ if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) == 'base64'))
+ {
+ $mode = SIMPLEPIE_CONSTRUCT_BASE64;
+ }
+ else
+ {
+ $mode = SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ if (isset($attribs['']['type']))
+ {
+ switch (strtolower(trim($attribs['']['type'])))
+ {
+ case 'text':
+ case 'text/plain':
+ return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+
+ case 'html':
+ case 'text/html':
+ return SIMPLEPIE_CONSTRUCT_HTML | $mode;
+
+ case 'xhtml':
+ case 'application/xhtml+xml':
+ return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
+
+ default:
+ return SIMPLEPIE_CONSTRUCT_NONE | $mode;
+ }
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+ }
+ }
+
+ function atom_10_construct_type($attribs)
+ {
+ if (isset($attribs['']['type']))
+ {
+ switch (strtolower(trim($attribs['']['type'])))
+ {
+ case 'text':
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+
+ case 'html':
+ return SIMPLEPIE_CONSTRUCT_HTML;
+
+ case 'xhtml':
+ return SIMPLEPIE_CONSTRUCT_XHTML;
+
+ default:
+ return SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ }
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+
+ function atom_10_content_construct_type($attribs)
+ {
+ if (isset($attribs['']['type']))
+ {
+ $type = strtolower(trim($attribs['']['type']));
+ switch ($type)
+ {
+ case 'text':
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+
+ case 'html':
+ return SIMPLEPIE_CONSTRUCT_HTML;
+
+ case 'xhtml':
+ return SIMPLEPIE_CONSTRUCT_XHTML;
+ }
+ if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) == 'text/')
+ {
+ return SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_BASE64;
+ }
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+ }
+
+ function is_isegment_nz_nc($string)
+ {
+ return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
+ }
+
+ function space_separated_tokens($string)
+ {
+ $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
+ $string_length = strlen($string);
+
+ $position = strspn($string, $space_characters);
+ $tokens = array();
+
+ while ($position < $string_length)
+ {
+ $len = strcspn($string, $space_characters, $position);
+ $tokens[] = substr($string, $position, $len);
+ $position += $len;
+ $position += strspn($string, $space_characters, $position);
+ }
+
+ return $tokens;
+ }
+
+ function array_unique($array)
+ {
+ if (version_compare(PHP_VERSION, '5.2', '>='))
+ {
+ return array_unique($array);
+ }
+ else
+ {
+ $array = (array) $array;
+ $new_array = array();
+ $new_array_strings = array();
+ foreach ($array as $key => $value)
+ {
+ if (is_object($value))
+ {
+ if (method_exists($value, '__toString'))
+ {
+ $cmp = $value->__toString();
+ }
+ else
+ {
+ trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
+ }
+ }
+ elseif (is_array($value))
+ {
+ $cmp = (string) reset($value);
+ }
+ else
+ {
+ $cmp = (string) $value;
+ }
+ if (!in_array($cmp, $new_array_strings))
+ {
+ $new_array[$key] = $value;
+ $new_array_strings[] = $cmp;
+ }
+ }
+ return $new_array;
+ }
+ }
+
+ /**
+ * Converts a unicode codepoint to a UTF-8 character
+ *
+ * @static
+ * @access public
+ * @param int $codepoint Unicode codepoint
+ * @return string UTF-8 character
+ */
+ function codepoint_to_utf8($codepoint)
+ {
+ static $cache = array();
+ $codepoint = (int) $codepoint;
+ if (isset($cache[$codepoint]))
+ {
+ return $cache[$codepoint];
+ }
+ elseif ($codepoint < 0)
+ {
+ return $cache[$codepoint] = false;
+ }
+ else if ($codepoint <= 0x7f)
+ {
+ return $cache[$codepoint] = chr($codepoint);
+ }
+ else if ($codepoint <= 0x7ff)
+ {
+ return $cache[$codepoint] = chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else if ($codepoint <= 0xffff)
+ {
+ return $cache[$codepoint] = chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else if ($codepoint <= 0x10ffff)
+ {
+ return $cache[$codepoint] = chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else
+ {
+ // U+FFFD REPLACEMENT CHARACTER
+ return $cache[$codepoint] = "\xEF\xBF\xBD";
+ }
+ }
+
+ /**
+ * Re-implementation of PHP 5's stripos()
+ *
+ * Returns the numeric position of the first occurrence of needle in the
+ * haystack string.
+ *
+ * @static
+ * @access string
+ * @param object $haystack
+ * @param string $needle Note that the needle may be a string of one or more
+ * characters. If needle is not a string, it is converted to an integer
+ * and applied as the ordinal value of a character.
+ * @param int $offset The optional offset parameter allows you to specify which
+ * character in haystack to start searching. The position returned is still
+ * relative to the beginning of haystack.
+ * @return bool If needle is not found, stripos() will return boolean false.
+ */
+ function stripos($haystack, $needle, $offset = 0)
+ {
+ if (function_exists('stripos'))
+ {
+ return stripos($haystack, $needle, $offset);
+ }
+ else
+ {
+ if (is_string($needle))
+ {
+ $needle = strtolower($needle);
+ }
+ elseif (is_int($needle) || is_bool($needle) || is_double($needle))
+ {
+ $needle = strtolower(chr($needle));
+ }
+ else
+ {
+ trigger_error('needle is not a string or an integer', E_USER_WARNING);
+ return false;
+ }
+
+ return strpos(strtolower($haystack), $needle, $offset);
+ }
+ }
+
+ /**
+ * Similar to parse_str()
+ *
+ * Returns an associative array of name/value pairs, where the value is an
+ * array of values that have used the same name
+ *
+ * @static
+ * @access string
+ * @param string $str The input string.
+ * @return array
+ */
+ function parse_str($str)
+ {
+ $return = array();
+ $str = explode('&', $str);
+
+ foreach ($str as $section)
+ {
+ if (strpos($section, '=') !== false)
+ {
+ list($name, $value) = explode('=', $section, 2);
+ $return[urldecode($name)][] = urldecode($value);
+ }
+ else
+ {
+ $return[urldecode($section)][] = null;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Detect XML encoding, as per XML 1.0 Appendix F.1
+ *
+ * @todo Add support for EBCDIC
+ * @param string $data XML data
+ * @return array Possible encodings
+ */
+ function xml_encoding($data)
+ {
+ // UTF-32 Big Endian BOM
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+ {
+ $encoding[] = 'UTF-32BE';
+ }
+ // UTF-32 Little Endian BOM
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+ {
+ $encoding[] = 'UTF-32LE';
+ }
+ // UTF-16 Big Endian BOM
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
+ {
+ $encoding[] = 'UTF-16BE';
+ }
+ // UTF-16 Little Endian BOM
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
+ {
+ $encoding[] = 'UTF-16LE';
+ }
+ // UTF-8 BOM
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+ {
+ $encoding[] = 'UTF-8';
+ }
+ // UTF-32 Big Endian Without BOM
+ elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
+ {
+ if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
+ {
+ $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-32BE';
+ }
+ // UTF-32 Little Endian Without BOM
+ elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
+ {
+ if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
+ {
+ $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-32LE';
+ }
+ // UTF-16 Big Endian Without BOM
+ elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
+ {
+ if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
+ {
+ $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-16BE';
+ }
+ // UTF-16 Little Endian Without BOM
+ elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
+ {
+ if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
+ {
+ $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-16LE';
+ }
+ // US-ASCII (or superset)
+ elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
+ {
+ if ($pos = strpos($data, "\x3F\x3E"))
+ {
+ $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-8';
+ }
+ // Fallback to UTF-8
+ else
+ {
+ $encoding[] = 'UTF-8';
+ }
+ return $encoding;
+ }
+}
+
+/**
+ * Decode HTML Entities
+ *
+ * This implements HTML5 as of revision 967 (2007-06-28)
+ *
+ * @package SimplePie
+ */
+class SimplePie_Decode_HTML_Entities
+{
+ /**
+ * Data to be parsed
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Currently consumed bytes
+ *
+ * @access private
+ * @var string
+ */
+ var $consumed = '';
+
+ /**
+ * Position of the current byte being parsed
+ *
+ * @access private
+ * @var int
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ function SimplePie_Decode_HTML_Entities($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return string Output data
+ */
+ function parse()
+ {
+ while (($this->position = strpos($this->data, '&', $this->position)) !== false)
+ {
+ $this->consume();
+ $this->entity();
+ $this->consumed = '';
+ }
+ return $this->data;
+ }
+
+ /**
+ * Consume the next byte
+ *
+ * @access private
+ * @return mixed The next byte, or false, if there is no more data
+ */
+ function consume()
+ {
+ if (isset($this->data[$this->position]))
+ {
+ $this->consumed .= $this->data[$this->position];
+ return $this->data[$this->position++];
+ }
+ else
+ {
+ $this->consumed = false;
+ return false;
+ }
+ }
+
+ /**
+ * Consume a range of characters
+ *
+ * @access private
+ * @param string $chars Characters to consume
+ * @return mixed A series of characters that match the range, or false
+ */
+ function consume_range($chars)
+ {
+ if ($len = strspn($this->data, $chars, $this->position))
+ {
+ $data = substr($this->data, $this->position, $len);
+ $this->consumed .= $data;
+ $this->position += $len;
+ return $data;
+ }
+ else
+ {
+ $this->consumed = false;
+ return false;
+ }
+ }
+
+ /**
+ * Unconsume one byte
+ *
+ * @access private
+ */
+ function unconsume()
+ {
+ $this->consumed = substr($this->consumed, 0, -1);
+ $this->position--;
+ }
+
+ /**
+ * Decode an entity
+ *
+ * @access private
+ */
+ function entity()
+ {
+ switch ($this->consume())
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0B":
+ case "\x0B":
+ case "\x0C":
+ case "\x20":
+ case "\x3C":
+ case "\x26":
+ case false:
+ break;
+
+ case "\x23":
+ switch ($this->consume())
+ {
+ case "\x78":
+ case "\x58":
+ $range = '0123456789ABCDEFabcdef';
+ $hex = true;
+ break;
+
+ default:
+ $range = '0123456789';
+ $hex = false;
+ $this->unconsume();
+ break;
+ }
+
+ if ($codepoint = $this->consume_range($range))
+ {
+ static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
+
+ if ($hex)
+ {
+ $codepoint = hexdec($codepoint);
+ }
+ else
+ {
+ $codepoint = intval($codepoint);
+ }
+
+ if (isset($windows_1252_specials[$codepoint]))
+ {
+ $replacement = $windows_1252_specials[$codepoint];
+ }
+ else
+ {
+ $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
+ }
+
+ if ($this->consume() != ';')
+ {
+ $this->unconsume();
+ }
+
+ $consumed_length = strlen($this->consumed);
+ $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
+ $this->position += strlen($replacement) - $consumed_length;
+ }
+ break;
+
+ default:
+ static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
+
+ for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
+ {
+ $consumed = substr($this->consumed, 1);
+ if (isset($entities[$consumed]))
+ {
+ $match = $consumed;
+ }
+ }
+
+ if ($match !== null)
+ {
+ $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
+ $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * Date Parser
+ *
+ * @package SimplePie
+ */
+class SimplePie_Parse_Date
+{
+ /**
+ * Input data
+ *
+ * @access protected
+ * @var string
+ */
+ var $date;
+
+ /**
+ * List of days, calendar day name => ordinal day number in the week
+ *
+ * @access protected
+ * @var array
+ */
+ var $day = array(
+ // English
+ 'mon' => 1,
+ 'monday' => 1,
+ 'tue' => 2,
+ 'tuesday' => 2,
+ 'wed' => 3,
+ 'wednesday' => 3,
+ 'thu' => 4,
+ 'thursday' => 4,
+ 'fri' => 5,
+ 'friday' => 5,
+ 'sat' => 6,
+ 'saturday' => 6,
+ 'sun' => 7,
+ 'sunday' => 7,
+ // Dutch
+ 'maandag' => 1,
+ 'dinsdag' => 2,
+ 'woensdag' => 3,
+ 'donderdag' => 4,
+ 'vrijdag' => 5,
+ 'zaterdag' => 6,
+ 'zondag' => 7,
+ // French
+ 'lundi' => 1,
+ 'mardi' => 2,
+ 'mercredi' => 3,
+ 'jeudi' => 4,
+ 'vendredi' => 5,
+ 'samedi' => 6,
+ 'dimanche' => 7,
+ // German
+ 'montag' => 1,
+ 'dienstag' => 2,
+ 'mittwoch' => 3,
+ 'donnerstag' => 4,
+ 'freitag' => 5,
+ 'samstag' => 6,
+ 'sonnabend' => 6,
+ 'sonntag' => 7,
+ // Italian
+ 'lunedì' => 1,
+ 'martedì' => 2,
+ 'mercoledì' => 3,
+ 'giovedì' => 4,
+ 'venerdì' => 5,
+ 'sabato' => 6,
+ 'domenica' => 7,
+ // Spanish
+ 'lunes' => 1,
+ 'martes' => 2,
+ 'miércoles' => 3,
+ 'jueves' => 4,
+ 'viernes' => 5,
+ 'sábado' => 6,
+ 'domingo' => 7,
+ // Finnish
+ 'maanantai' => 1,
+ 'tiistai' => 2,
+ 'keskiviikko' => 3,
+ 'torstai' => 4,
+ 'perjantai' => 5,
+ 'lauantai' => 6,
+ 'sunnuntai' => 7,
+ // Hungarian
+ 'hétfő' => 1,
+ 'kedd' => 2,
+ 'szerda' => 3,
+ 'csütörtok' => 4,
+ 'péntek' => 5,
+ 'szombat' => 6,
+ 'vasárnap' => 7,
+ // Greek
+ 'Δευ' => 1,
+ 'ΤÏι' => 2,
+ 'Τετ' => 3,
+ 'Πεμ' => 4,
+ 'ΠαÏ' => 5,
+ 'Σαβ' => 6,
+ 'ΚυÏ' => 7,
+ );
+
+ /**
+ * List of months, calendar month name => calendar month number
+ *
+ * @access protected
+ * @var array
+ */
+ var $month = array(
+ // English
+ 'jan' => 1,
+ 'january' => 1,
+ 'feb' => 2,
+ 'february' => 2,
+ 'mar' => 3,
+ 'march' => 3,
+ 'apr' => 4,
+ 'april' => 4,
+ 'may' => 5,
+ // No long form of May
+ 'jun' => 6,
+ 'june' => 6,
+ 'jul' => 7,
+ 'july' => 7,
+ 'aug' => 8,
+ 'august' => 8,
+ 'sep' => 9,
+ 'september' => 8,
+ 'oct' => 10,
+ 'october' => 10,
+ 'nov' => 11,
+ 'november' => 11,
+ 'dec' => 12,
+ 'december' => 12,
+ // Dutch
+ 'januari' => 1,
+ 'februari' => 2,
+ 'maart' => 3,
+ 'april' => 4,
+ 'mei' => 5,
+ 'juni' => 6,
+ 'juli' => 7,
+ 'augustus' => 8,
+ 'september' => 9,
+ 'oktober' => 10,
+ 'november' => 11,
+ 'december' => 12,
+ // French
+ 'janvier' => 1,
+ 'février' => 2,
+ 'mars' => 3,
+ 'avril' => 4,
+ 'mai' => 5,
+ 'juin' => 6,
+ 'juillet' => 7,
+ 'août' => 8,
+ 'septembre' => 9,
+ 'octobre' => 10,
+ 'novembre' => 11,
+ 'décembre' => 12,
+ // German
+ 'januar' => 1,
+ 'februar' => 2,
+ 'märz' => 3,
+ 'april' => 4,
+ 'mai' => 5,
+ 'juni' => 6,
+ 'juli' => 7,
+ 'august' => 8,
+ 'september' => 9,
+ 'oktober' => 10,
+ 'november' => 11,
+ 'dezember' => 12,
+ // Italian
+ 'gennaio' => 1,
+ 'febbraio' => 2,
+ 'marzo' => 3,
+ 'aprile' => 4,
+ 'maggio' => 5,
+ 'giugno' => 6,
+ 'luglio' => 7,
+ 'agosto' => 8,
+ 'settembre' => 9,
+ 'ottobre' => 10,
+ 'novembre' => 11,
+ 'dicembre' => 12,
+ // Spanish
+ 'enero' => 1,
+ 'febrero' => 2,
+ 'marzo' => 3,
+ 'abril' => 4,
+ 'mayo' => 5,
+ 'junio' => 6,
+ 'julio' => 7,
+ 'agosto' => 8,
+ 'septiembre' => 9,
+ 'setiembre' => 9,
+ 'octubre' => 10,
+ 'noviembre' => 11,
+ 'diciembre' => 12,
+ // Finnish
+ 'tammikuu' => 1,
+ 'helmikuu' => 2,
+ 'maaliskuu' => 3,
+ 'huhtikuu' => 4,
+ 'toukokuu' => 5,
+ 'kesäkuu' => 6,
+ 'heinäkuu' => 7,
+ 'elokuu' => 8,
+ 'suuskuu' => 9,
+ 'lokakuu' => 10,
+ 'marras' => 11,
+ 'joulukuu' => 12,
+ // Hungarian
+ 'január' => 1,
+ 'február' => 2,
+ 'március' => 3,
+ 'április' => 4,
+ 'május' => 5,
+ 'június' => 6,
+ 'július' => 7,
+ 'augusztus' => 8,
+ 'szeptember' => 9,
+ 'október' => 10,
+ 'november' => 11,
+ 'december' => 12,
+ // Greek
+ 'Ιαν' => 1,
+ 'Φεβ' => 2,
+ 'Μάώ' => 3,
+ 'Μαώ' => 3,
+ 'ΑπÏ' => 4,
+ 'Μάι' => 5,
+ 'Μαϊ' => 5,
+ 'Μαι' => 5,
+ 'ΙοÏν' => 6,
+ 'Ιον' => 6,
+ 'ΙοÏλ' => 7,
+ 'Ιολ' => 7,
+ 'ΑÏγ' => 8,
+ 'Αυγ' => 8,
+ 'Σεπ' => 9,
+ 'Οκτ' => 10,
+ 'Îοέ' => 11,
+ 'Δεκ' => 12,
+ );
+
+ /**
+ * List of timezones, abbreviation => offset from UTC
+ *
+ * @access protected
+ * @var array
+ */
+ var $timezone = array(
+ 'ACDT' => 37800,
+ 'ACIT' => 28800,
+ 'ACST' => 34200,
+ 'ACT' => -18000,
+ 'ACWDT' => 35100,
+ 'ACWST' => 31500,
+ 'AEDT' => 39600,
+ 'AEST' => 36000,
+ 'AFT' => 16200,
+ 'AKDT' => -28800,
+ 'AKST' => -32400,
+ 'AMDT' => 18000,
+ 'AMT' => -14400,
+ 'ANAST' => 46800,
+ 'ANAT' => 43200,
+ 'ART' => -10800,
+ 'AZOST' => -3600,
+ 'AZST' => 18000,
+ 'AZT' => 14400,
+ 'BIOT' => 21600,
+ 'BIT' => -43200,
+ 'BOT' => -14400,
+ 'BRST' => -7200,
+ 'BRT' => -10800,
+ 'BST' => 3600,
+ 'BTT' => 21600,
+ 'CAST' => 18000,
+ 'CAT' => 7200,
+ 'CCT' => 23400,
+ 'CDT' => -18000,
+ 'CEDT' => 7200,
+ 'CET' => 3600,
+ 'CGST' => -7200,
+ 'CGT' => -10800,
+ 'CHADT' => 49500,
+ 'CHAST' => 45900,
+ 'CIST' => -28800,
+ 'CKT' => -36000,
+ 'CLDT' => -10800,
+ 'CLST' => -14400,
+ 'COT' => -18000,
+ 'CST' => -21600,
+ 'CVT' => -3600,
+ 'CXT' => 25200,
+ 'DAVT' => 25200,
+ 'DTAT' => 36000,
+ 'EADT' => -18000,
+ 'EAST' => -21600,
+ 'EAT' => 10800,
+ 'ECT' => -18000,
+ 'EDT' => -14400,
+ 'EEST' => 10800,
+ 'EET' => 7200,
+ 'EGT' => -3600,
+ 'EKST' => 21600,
+ 'EST' => -18000,
+ 'FJT' => 43200,
+ 'FKDT' => -10800,
+ 'FKST' => -14400,
+ 'FNT' => -7200,
+ 'GALT' => -21600,
+ 'GEDT' => 14400,
+ 'GEST' => 10800,
+ 'GFT' => -10800,
+ 'GILT' => 43200,
+ 'GIT' => -32400,
+ 'GST' => 14400,
+ 'GST' => -7200,
+ 'GYT' => -14400,
+ 'HAA' => -10800,
+ 'HAC' => -18000,
+ 'HADT' => -32400,
+ 'HAE' => -14400,
+ 'HAP' => -25200,
+ 'HAR' => -21600,
+ 'HAST' => -36000,
+ 'HAT' => -9000,
+ 'HAY' => -28800,
+ 'HKST' => 28800,
+ 'HMT' => 18000,
+ 'HNA' => -14400,
+ 'HNC' => -21600,
+ 'HNE' => -18000,
+ 'HNP' => -28800,
+ 'HNR' => -25200,
+ 'HNT' => -12600,
+ 'HNY' => -32400,
+ 'IRDT' => 16200,
+ 'IRKST' => 32400,
+ 'IRKT' => 28800,
+ 'IRST' => 12600,
+ 'JFDT' => -10800,
+ 'JFST' => -14400,
+ 'JST' => 32400,
+ 'KGST' => 21600,
+ 'KGT' => 18000,
+ 'KOST' => 39600,
+ 'KOVST' => 28800,
+ 'KOVT' => 25200,
+ 'KRAST' => 28800,
+ 'KRAT' => 25200,
+ 'KST' => 32400,
+ 'LHDT' => 39600,
+ 'LHST' => 37800,
+ 'LINT' => 50400,
+ 'LKT' => 21600,
+ 'MAGST' => 43200,
+ 'MAGT' => 39600,
+ 'MAWT' => 21600,
+ 'MDT' => -21600,
+ 'MESZ' => 7200,
+ 'MEZ' => 3600,
+ 'MHT' => 43200,
+ 'MIT' => -34200,
+ 'MNST' => 32400,
+ 'MSDT' => 14400,
+ 'MSST' => 10800,
+ 'MST' => -25200,
+ 'MUT' => 14400,
+ 'MVT' => 18000,
+ 'MYT' => 28800,
+ 'NCT' => 39600,
+ 'NDT' => -9000,
+ 'NFT' => 41400,
+ 'NMIT' => 36000,
+ 'NOVST' => 25200,
+ 'NOVT' => 21600,
+ 'NPT' => 20700,
+ 'NRT' => 43200,
+ 'NST' => -12600,
+ 'NUT' => -39600,
+ 'NZDT' => 46800,
+ 'NZST' => 43200,
+ 'OMSST' => 25200,
+ 'OMST' => 21600,
+ 'PDT' => -25200,
+ 'PET' => -18000,
+ 'PETST' => 46800,
+ 'PETT' => 43200,
+ 'PGT' => 36000,
+ 'PHOT' => 46800,
+ 'PHT' => 28800,
+ 'PKT' => 18000,
+ 'PMDT' => -7200,
+ 'PMST' => -10800,
+ 'PONT' => 39600,
+ 'PST' => -28800,
+ 'PWT' => 32400,
+ 'PYST' => -10800,
+ 'PYT' => -14400,
+ 'RET' => 14400,
+ 'ROTT' => -10800,
+ 'SAMST' => 18000,
+ 'SAMT' => 14400,
+ 'SAST' => 7200,
+ 'SBT' => 39600,
+ 'SCDT' => 46800,
+ 'SCST' => 43200,
+ 'SCT' => 14400,
+ 'SEST' => 3600,
+ 'SGT' => 28800,
+ 'SIT' => 28800,
+ 'SRT' => -10800,
+ 'SST' => -39600,
+ 'SYST' => 10800,
+ 'SYT' => 7200,
+ 'TFT' => 18000,
+ 'THAT' => -36000,
+ 'TJT' => 18000,
+ 'TKT' => -36000,
+ 'TMT' => 18000,
+ 'TOT' => 46800,
+ 'TPT' => 32400,
+ 'TRUT' => 36000,
+ 'TVT' => 43200,
+ 'TWT' => 28800,
+ 'UYST' => -7200,
+ 'UYT' => -10800,
+ 'UZT' => 18000,
+ 'VET' => -14400,
+ 'VLAST' => 39600,
+ 'VLAT' => 36000,
+ 'VOST' => 21600,
+ 'VUT' => 39600,
+ 'WAST' => 7200,
+ 'WAT' => 3600,
+ 'WDT' => 32400,
+ 'WEST' => 3600,
+ 'WFT' => 43200,
+ 'WIB' => 25200,
+ 'WIT' => 32400,
+ 'WITA' => 28800,
+ 'WKST' => 18000,
+ 'WST' => 28800,
+ 'YAKST' => 36000,
+ 'YAKT' => 32400,
+ 'YAPT' => 36000,
+ 'YEKST' => 21600,
+ 'YEKT' => 18000,
+ );
+
+ /**
+ * Cached PCRE for SimplePie_Parse_Date::$day
+ *
+ * @access protected
+ * @var string
+ */
+ var $day_pcre;
+
+ /**
+ * Cached PCRE for SimplePie_Parse_Date::$month
+ *
+ * @access protected
+ * @var string
+ */
+ var $month_pcre;
+
+ /**
+ * Array of user-added callback methods
+ *
+ * @access private
+ * @var array
+ */
+ var $built_in = array();
+
+ /**
+ * Array of user-added callback methods
+ *
+ * @access private
+ * @var array
+ */
+ var $user = array();
+
+ /**
+ * Create new SimplePie_Parse_Date object, and set self::day_pcre,
+ * self::month_pcre, and self::built_in
+ *
+ * @access private
+ */
+ function SimplePie_Parse_Date()
+ {
+ $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
+ $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
+
+ static $cache;
+ if (!isset($cache[get_class($this)]))
+ {
+ if (extension_loaded('Reflection'))
+ {
+ $class = new ReflectionClass(get_class($this));
+ $methods = $class->getMethods();
+ $all_methods = array();
+ foreach ($methods as $method)
+ {
+ $all_methods[] = $method->getName();
+ }
+ }
+ else
+ {
+ $all_methods = get_class_methods($this);
+ }
+
+ foreach ($all_methods as $method)
+ {
+ if (strtolower(substr($method, 0, 5)) === 'date_')
+ {
+ $cache[get_class($this)][] = $method;
+ }
+ }
+ }
+
+ foreach ($cache[get_class($this)] as $method)
+ {
+ $this->built_in[] = $method;
+ }
+ }
+
+ /**
+ * Get the object
+ *
+ * @access public
+ */
+ function get()
+ {
+ static $object;
+ if (!$object)
+ {
+ $object = new SimplePie_Parse_Date;
+ }
+ return $object;
+ }
+
+ /**
+ * Parse a date
+ *
+ * @final
+ * @access public
+ * @param string $date Date to parse
+ * @return int Timestamp corresponding to date string, or false on failure
+ */
+ function parse($date)
+ {
+ foreach ($this->user as $method)
+ {
+ if (($returned = call_user_func($method, $date)) !== false)
+ {
+ return $returned;
+ }
+ }
+
+ foreach ($this->built_in as $method)
+ {
+ if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
+ {
+ return $returned;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Add a callback method to parse a date
+ *
+ * @final
+ * @access public
+ * @param callback $callback
+ */
+ function add_callback($callback)
+ {
+ if (is_callable($callback))
+ {
+ $this->user[] = $callback;
+ }
+ else
+ {
+ trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
+ }
+ }
+
+ /**
+ * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
+ * well as allowing any of upper or lower case "T", horizontal tabs, or
+ * spaces to be used as the time separator (including more than one))
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ function date_w3cdtf($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $year = '([0-9]{4})';
+ $month = $day = $hour = $minute = $second = '([0-9]{2})';
+ $decimal = '([0-9]*)';
+ $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
+ $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Year
+ 2: Month
+ 3: Day
+ 4: Hour
+ 5: Minute
+ 6: Second
+ 7: Decimal fraction of a second
+ 8: Zulu
+ 9: Timezone ±
+ 10: Timezone hours
+ 11: Timezone minutes
+ */
+
+ // Fill in empty matches
+ for ($i = count($match); $i <= 3; $i++)
+ {
+ $match[$i] = '1';
+ }
+
+ for ($i = count($match); $i <= 7; $i++)
+ {
+ $match[$i] = '0';
+ }
+
+ // Numeric timezone
+ if (isset($match[9]) && $match[9] !== '')
+ {
+ $timezone = $match[10] * 3600;
+ $timezone += $match[11] * 60;
+ if ($match[9] === '-')
+ {
+ $timezone = 0 - $timezone;
+ }
+ }
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Convert the number of seconds to an integer, taking decimals into account
+ $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
+
+ return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Remove RFC822 comments
+ *
+ * @access protected
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ function remove_rfc2822_comments($string)
+ {
+ $string = (string) $string;
+ $position = 0;
+ $length = strlen($string);
+ $depth = 0;
+
+ $output = '';
+
+ while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+ {
+ $output .= substr($string, $position, $pos - $position);
+ $position = $pos + 1;
+ if ($string[$pos - 1] !== '\\')
+ {
+ $depth++;
+ while ($depth && $position < $length)
+ {
+ $position += strcspn($string, '()', $position);
+ if ($string[$position - 1] === '\\')
+ {
+ $position++;
+ continue;
+ }
+ elseif (isset($string[$position]))
+ {
+ switch ($string[$position])
+ {
+ case '(':
+ $depth++;
+ break;
+
+ case ')':
+ $depth--;
+ break;
+ }
+ $position++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ $output .= '(';
+ }
+ }
+ $output .= substr($string, $position);
+
+ return $output;
+ }
+
+ /**
+ * Parse RFC2822's date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ function date_rfc2822($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $wsp = '[\x09\x20]';
+ $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
+ $optional_fws = $fws . '?';
+ $day_name = $this->day_pcre;
+ $month = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $hour = $minute = $second = '([0-9]{2})';
+ $year = '([0-9]{2,4})';
+ $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
+ $character_zone = '([A-Z]{1,5})';
+ $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
+ $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
+ }
+ if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Day
+ 3: Month
+ 4: Year
+ 5: Hour
+ 6: Minute
+ 7: Second
+ 8: Timezone ±
+ 9: Timezone hours
+ 10: Timezone minutes
+ 11: Alphabetic timezone
+ */
+
+ // Find the month number
+ $month = $this->month[strtolower($match[3])];
+
+ // Numeric timezone
+ if ($match[8] !== '')
+ {
+ $timezone = $match[9] * 3600;
+ $timezone += $match[10] * 60;
+ if ($match[8] === '-')
+ {
+ $timezone = 0 - $timezone;
+ }
+ }
+ // Character timezone
+ elseif (isset($this->timezone[strtoupper($match[11])]))
+ {
+ $timezone = $this->timezone[strtoupper($match[11])];
+ }
+ // Assume everything else to be -0000
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Deal with 2/3 digit years
+ if ($match[4] < 50)
+ {
+ $match[4] += 2000;
+ }
+ elseif ($match[4] < 1000)
+ {
+ $match[4] += 1900;
+ }
+
+ // Second is optional, if it is empty set it to zero
+ if ($match[7] !== '')
+ {
+ $second = $match[7];
+ }
+ else
+ {
+ $second = 0;
+ }
+
+ return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse RFC850's date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ function date_rfc850($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $space = '[\x09\x20]+';
+ $day_name = $this->day_pcre;
+ $month = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $year = $hour = $minute = $second = '([0-9]{2})';
+ $zone = '([A-Z]{1,5})';
+ $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Day
+ 3: Month
+ 4: Year
+ 5: Hour
+ 6: Minute
+ 7: Second
+ 8: Timezone
+ */
+
+ // Month
+ $month = $this->month[strtolower($match[3])];
+
+ // Character timezone
+ if (isset($this->timezone[strtoupper($match[8])]))
+ {
+ $timezone = $this->timezone[strtoupper($match[8])];
+ }
+ // Assume everything else to be -0000
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Deal with 2 digit year
+ if ($match[4] < 50)
+ {
+ $match[4] += 2000;
+ }
+ else
+ {
+ $match[4] += 1900;
+ }
+
+ return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse C99's asctime()'s date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ function date_asctime($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $space = '[\x09\x20]+';
+ $wday_name = $this->day_pcre;
+ $mon_name = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $hour = $sec = $min = '([0-9]{2})';
+ $year = '([0-9]{4})';
+ $terminator = '\x0A?\x00?';
+ $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Month
+ 3: Day
+ 4: Hour
+ 5: Minute
+ 6: Second
+ 7: Year
+ */
+
+ $month = $this->month[strtolower($match[2])];
+ return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse dates using strtotime()
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ function date_strtotime($date)
+ {
+ $strtotime = strtotime($date);
+ if ($strtotime === -1 || $strtotime === false)
+ {
+ return false;
+ }
+ else
+ {
+ return $strtotime;
+ }
+ }
+}
+
+/**
+ * Content-type sniffing
+ *
+ * @package SimplePie
+ */
+class SimplePie_Content_Type_Sniffer
+{
+ /**
+ * File object
+ *
+ * @var SimplePie_File
+ * @access private
+ */
+ var $file;
+
+ /**
+ * Create an instance of the class with the input file
+ *
+ * @access public
+ * @param SimplePie_Content_Type_Sniffer $file Input file
+ */
+ function SimplePie_Content_Type_Sniffer($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Get the Content-Type of the specified file
+ *
+ * @access public
+ * @return string Actual Content-Type
+ */
+ function get_type()
+ {
+ if (isset($this->file->headers['content-type']))
+ {
+ if (!isset($this->file->headers['content-encoding'])
+ && ($this->file->headers['content-type'] === 'text/plain'
+ || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
+ || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'))
+ {
+ return $this->text_or_binary();
+ }
+
+ if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
+ {
+ $official = substr($this->file->headers['content-type'], 0, $pos);
+ }
+ else
+ {
+ $official = $this->file->headers['content-type'];
+ }
+ $official = strtolower($official);
+
+ if ($official === 'unknown/unknown'
+ || $official === 'application/unknown')
+ {
+ return $this->unknown();
+ }
+ elseif (substr($official, -4) === '+xml'
+ || $official === 'text/xml'
+ || $official === 'application/xml')
+ {
+ return $official;
+ }
+ elseif (substr($official, 0, 6) === 'image/')
+ {
+ if ($return = $this->image())
+ {
+ return $return;
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ elseif ($official === 'text/html')
+ {
+ return $this->feed_or_html();
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ else
+ {
+ return $this->unknown();
+ }
+ }
+
+ /**
+ * Sniff text or binary
+ *
+ * @access private
+ * @return string Actual Content-Type
+ */
+ function text_or_binary()
+ {
+ if (substr($this->file->body, 0, 2) === "\xFE\xFF"
+ || substr($this->file->body, 0, 2) === "\xFF\xFE"
+ || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
+ || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
+ {
+ return 'text/plain';
+ }
+ elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
+ {
+ return 'application/octect-stream';
+ }
+ else
+ {
+ return 'text/plain';
+ }
+ }
+
+ /**
+ * Sniff unknown
+ *
+ * @access private
+ * @return string Actual Content-Type
+ */
+ function unknown()
+ {
+ $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
+ if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
+ || strtolower(substr($this->file->body, $ws, 5)) === '<html'
+ || strtolower(substr($this->file->body, $ws, 7)) === '<script')
+ {
+ return 'text/html';
+ }
+ elseif (substr($this->file->body, 0, 5) === '%PDF-')
+ {
+ return 'application/pdf';
+ }
+ elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
+ {
+ return 'application/postscript';
+ }
+ elseif (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ else
+ {
+ return $this->text_or_binary();
+ }
+ }
+
+ /**
+ * Sniff images
+ *
+ * @access private
+ * @return string Actual Content-Type
+ */
+ function image()
+ {
+ if (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Sniff HTML
+ *
+ * @access private
+ * @return string Actual Content-Type
+ */
+ function feed_or_html()
+ {
+ $len = strlen($this->file->body);
+ $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
+
+ while ($pos < $len)
+ {
+ switch ($this->file->body[$pos])
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0D":
+ case "\x20":
+ $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
+ continue 2;
+
+ case '<':
+ $pos++;
+ break;
+
+ default:
+ return 'text/html';
+ }
+
+ if (substr($this->file->body, $pos, 3) === '!--')
+ {
+ $pos += 3;
+ if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
+ {
+ $pos += 3;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '!')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
+ {
+ $pos++;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '?')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
+ {
+ $pos += 2;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 3) === 'rss'
+ || substr($this->file->body, $pos, 7) === 'rdf:RDF')
+ {
+ return 'application/rss+xml';
+ }
+ elseif (substr($this->file->body, $pos, 4) === 'feed')
+ {
+ return 'application/atom+xml';
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+
+ return 'text/html';
+ }
+}
+
+/**
+ * Parses the XML Declaration
+ *
+ * @package SimplePie
+ */
+class SimplePie_XML_Declaration_Parser
+{
+ /**
+ * XML Version
+ *
+ * @access public
+ * @var string
+ */
+ var $version = '1.0';
+
+ /**
+ * Encoding
+ *
+ * @access public
+ * @var string
+ */
+ var $encoding = 'UTF-8';
+
+ /**
+ * Standalone
+ *
+ * @access public
+ * @var bool
+ */
+ var $standalone = false;
+
+ /**
+ * Current state of the state machine
+ *
+ * @access private
+ * @var string
+ */
+ var $state = 'before_version_name';
+
+ /**
+ * Input data
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @access private
+ * @var int
+ */
+ var $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ * @access private
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ function SimplePie_XML_Declaration_Parser($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return bool true on success, false on failure
+ */
+ function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit')
+ {
+ return true;
+ }
+ else
+ {
+ $this->version = '';
+ $this->encoding = '';
+ $this->standalone = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @access private
+ * @return bool true if there is further data, false if not
+ */
+ function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * Advance past any whitespace
+ *
+ * @return int Number of whitespace characters passed
+ */
+ function skip_whitespace()
+ {
+ $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
+ $this->position += $whitespace;
+ return $whitespace;
+ }
+
+ /**
+ * Read value
+ */
+ function get_value()
+ {
+ $quote = substr($this->data, $this->position, 1);
+ if ($quote === '"' || $quote === "'")
+ {
+ $this->position++;
+ $len = strcspn($this->data, $quote, $this->position);
+ if ($this->has_data())
+ {
+ $value = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ return $value;
+ }
+ }
+ return false;
+ }
+
+ function before_version_name()
+ {
+ if ($this->skip_whitespace())
+ {
+ $this->state = 'version_name';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function version_name()
+ {
+ if (substr($this->data, $this->position, 7) === 'version')
+ {
+ $this->position += 7;
+ $this->skip_whitespace();
+ $this->state = 'version_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function version_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'version_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function version_value()
+ {
+ if ($this->version = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'encoding_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = 'standalone_name';
+ }
+ }
+
+ function encoding_name()
+ {
+ if (substr($this->data, $this->position, 8) === 'encoding')
+ {
+ $this->position += 8;
+ $this->skip_whitespace();
+ $this->state = 'encoding_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function encoding_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'encoding_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function encoding_value()
+ {
+ if ($this->encoding = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'standalone_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function standalone_name()
+ {
+ if (substr($this->data, $this->position, 10) === 'standalone')
+ {
+ $this->position += 10;
+ $this->skip_whitespace();
+ $this->state = 'standalone_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function standalone_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'standalone_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ function standalone_value()
+ {
+ if ($standalone = $this->get_value())
+ {
+ switch ($standalone)
+ {
+ case 'yes':
+ $this->standalone = true;
+ break;
+
+ case 'no':
+ $this->standalone = false;
+ break;
+
+ default:
+ $this->state = false;
+ return;
+ }
+
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = false;
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+}
+
+class SimplePie_Locator
+{
+ var $useragent;
+ var $timeout;
+ var $file;
+ var $local = array();
+ var $elsewhere = array();
+ var $file_class = 'SimplePie_File';
+ var $cached_entities = array();
+ var $http_base;
+ var $base;
+ var $base_location = 0;
+ var $checked_feeds = 0;
+ var $max_checked_feeds = 10;
+ var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
+
+ function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer')
+ {
+ $this->file =& $file;
+ $this->file_class = $file_class;
+ $this->useragent = $useragent;
+ $this->timeout = $timeout;
+ $this->max_checked_feeds = $max_checked_feeds;
+ $this->content_type_sniffer_class = $content_type_sniffer_class;
+ }
+
+ function find($type = SIMPLEPIE_LOCATOR_ALL)
+ {
+ if ($this->is_feed($this->file))
+ {
+ return $this->file;
+ }
+
+ if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+ {
+ $sniffer = new $this->content_type_sniffer_class($this->file);
+ if ($sniffer->get_type() !== 'text/html')
+ {
+ return null;
+ }
+ }
+
+ if ($type & ~SIMPLEPIE_LOCATOR_NONE)
+ {
+ $this->get_base();
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
+ {
+ return $working;
+ }
+
+ if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
+ {
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
+ {
+ return $working;
+ }
+ }
+ return null;
+ }
+
+ function is_feed(&$file)
+ {
+ if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+ {
+ $sniffer = new $this->content_type_sniffer_class($file);
+ $sniffed = $sniffer->get_type();
+ if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ function get_base()
+ {
+ $this->http_base = $this->file->url;
+ $this->base = $this->http_base;
+ $elements = SimplePie_Misc::get_element('base', $this->file->body);
+ foreach ($elements as $element)
+ {
+ if ($element['attribs']['href']['data'] !== '')
+ {
+ $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base);
+ $this->base_location = $element['offset'];
+ break;
+ }
+ }
+ }
+
+ function autodiscovery()
+ {
+ $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body));
+ $done = array();
+ foreach ($links as $link)
+ {
+ if ($this->checked_feeds == $this->max_checked_feeds)
+ {
+ break;
+ }
+ if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data']))
+ {
+ $rel = array_unique(SimplePie_Misc::space_separated_tokens(strtolower($link['attribs']['rel']['data'])));
+
+ if ($this->base_location < $link['offset'])
+ {
+ $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
+ }
+ else
+ {
+ $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
+ }
+
+ if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))))
+ {
+ $this->checked_feeds++;
+ $feed =& new $this->file_class($href, $this->timeout, 5, null, $this->useragent);
+ if ($this->is_feed($feed))
+ {
+ return $feed;
+ }
+ }
+ $done[] = $href;
+ }
+ }
+ return null;
+ }
+
+ function get_links()
+ {
+ $links = SimplePie_Misc::get_element('a', $this->file->body);
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['href']['data']))
+ {
+ $href = trim($link['attribs']['href']['data']);
+ $parsed = SimplePie_Misc::parse_url($href);
+ if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
+ {
+ if ($this->base_location < $link['offset'])
+ {
+ $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
+ }
+ else
+ {
+ $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
+ }
+
+ $current = SimplePie_Misc::parse_url($this->file->url);
+
+ if ($parsed['authority'] === '' || $parsed['authority'] == $current['authority'])
+ {
+ $this->local[] = $href;
+ }
+ else
+ {
+ $this->elsewhere[] = $href;
+ }
+ }
+ }
+ }
+ $this->local = array_unique($this->local);
+ $this->elsewhere = array_unique($this->elsewhere);
+ if (!empty($this->local) || !empty($this->elsewhere))
+ {
+ return true;
+ }
+ return null;
+ }
+
+ function extension(&$array)
+ {
+ foreach ($array as $key => $value)
+ {
+ if ($this->checked_feeds == $this->max_checked_feeds)
+ {
+ break;
+ }
+ if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
+ {
+ $this->checked_feeds++;
+ $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
+ if ($this->is_feed($feed))
+ {
+ return $feed;
+ }
+ else
+ {
+ unset($array[$key]);
+ }
+ }
+ }
+ return null;
+ }
+
+ function body(&$array)
+ {
+ foreach ($array as $key => $value)
+ {
+ if ($this->checked_feeds == $this->max_checked_feeds)
+ {
+ break;
+ }
+ if (preg_match('/(rss|rdf|atom|xml)/i', $value))
+ {
+ $this->checked_feeds++;
+ $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
+ if ($this->is_feed($feed))
+ {
+ return $feed;
+ }
+ else
+ {
+ unset($array[$key]);
+ }
+ }
+ }
+ return null;
+ }
+}
+
+class SimplePie_Parser
+{
+ var $error_code;
+ var $error_string;
+ var $current_line;
+ var $current_column;
+ var $current_byte;
+ var $separator = ' ';
+ var $feed = false;
+ var $namespace = array('');
+ var $element = array('');
+ var $xml_base = array('');
+ var $xml_base_explicit = array(false);
+ var $xml_lang = array('');
+ var $data = array();
+ var $datas = array(array());
+ var $current_xhtml_construct = -1;
+ var $encoding;
+
+ function parse(&$data, $encoding)
+ {
+ // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
+ if (strtoupper($encoding) == 'US-ASCII')
+ {
+ $this->encoding = 'UTF-8';
+ }
+ else
+ {
+ $this->encoding = $encoding;
+ }
+
+ // Strip BOM:
+ // UTF-32 Big Endian BOM
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-32 Little Endian BOM
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-16 Big Endian BOM
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-16 Little Endian BOM
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-8 BOM
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+ {
+ $data = substr($data, 3);
+ }
+
+ if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+ {
+ $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+ if ($declaration->parse())
+ {
+ $data = substr($data, $pos + 2);
+ $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+ }
+ else
+ {
+ $this->error_string = 'SimplePie bug! Please report this!';
+ return false;
+ }
+ }
+
+ // Work around libxml bug
+ $data = str_replace('&lt;', '&#60;', $data);
+ $data = str_replace('&gt;', '&#62;', $data);
+ $data = str_replace('&amp;', '&#38;', $data);
+ $data = str_replace('&apos;', '&#39;', $data);
+ $data = str_replace('&quot;', '&#34;', $data);
+
+ $return = true;
+
+ // Create the parser
+ $xml = xml_parser_create_ns($this->encoding, $this->separator);
+ xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
+ xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
+ xml_set_object($xml, $this);
+ xml_set_character_data_handler($xml, 'cdata');
+ xml_set_element_handler($xml, 'tag_open', 'tag_close');
+
+ // Parse!
+ if (!xml_parse($xml, $data, true))
+ {
+ $this->error_code = xml_get_error_code($xml);
+ $this->error_string = xml_error_string($this->error_code);
+ $return = false;
+ }
+ $this->current_line = xml_get_current_line_number($xml);
+ $this->current_column = xml_get_current_column_number($xml);
+ $this->current_byte = xml_get_current_byte_index($xml);
+ xml_parser_free($xml);
+ return $return;
+ }
+
+ function get_error_code()
+ {
+ return $this->error_code;
+ }
+
+ function get_error_string()
+ {
+ return $this->error_string;
+ }
+
+ function get_current_line()
+ {
+ return $this->current_line;
+ }
+
+ function get_current_column()
+ {
+ return $this->current_column;
+ }
+
+ function get_current_byte()
+ {
+ return $this->current_byte;
+ }
+
+ function get_data()
+ {
+ return $this->data;
+ }
+
+ function tag_open($parser, $tag, $attributes)
+ {
+ if ($this->feed === 0)
+ {
+ return;
+ }
+ elseif ($this->feed == false)
+ {
+ if (in_array($tag, array(
+ SIMPLEPIE_NAMESPACE_ATOM_10 . $this->separator . 'feed',
+ SIMPLEPIE_NAMESPACE_ATOM_03 . $this->separator . 'feed',
+ 'rss',
+ SIMPLEPIE_NAMESPACE_RDF . $this->separator . 'RDF'
+ )))
+ {
+ $this->feed = 1;
+ }
+ }
+ else
+ {
+ $this->feed++;
+ }
+
+ list($this->namespace[], $this->element[]) = $this->split_ns($tag);
+
+ $attribs = array();
+ foreach ($attributes as $name => $value)
+ {
+ list($attrib_namespace, $attribute) = $this->split_ns($name);
+ $attribs[$attrib_namespace][$attribute] = $value;
+ }
+
+ if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
+ {
+ $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
+ $this->xml_base_explicit[] = true;
+ }
+ else
+ {
+ $this->xml_base[] = end($this->xml_base);
+ $this->xml_base_explicit[] = end($this->xml_base_explicit);
+ }
+
+ if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
+ {
+ $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
+ }
+ else
+ {
+ $this->xml_lang[] = end($this->xml_lang);
+ }
+
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->current_xhtml_construct++;
+ if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML)
+ {
+ $this->data['data'] .= '<' . end($this->element);
+ if (isset($attribs['']))
+ {
+ foreach ($attribs[''] as $name => $value)
+ {
+ $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
+ }
+ }
+ $this->data['data'] .= '>';
+ }
+ }
+ else
+ {
+ $this->datas[] =& $this->data;
+ $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
+ $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
+ if ((end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] == 'xml')
+ || (end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] == 'xhtml'))
+ {
+ $this->current_xhtml_construct = 0;
+ }
+ }
+ }
+
+ function cdata($parser, $cdata)
+ {
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
+ }
+ elseif ($this->feed > 1)
+ {
+ $this->data['data'] .= $cdata;
+ }
+ }
+
+ function tag_close($parser, $tag)
+ {
+ if (!$this->feed)
+ {
+ return;
+ }
+
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->current_xhtml_construct--;
+ if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
+ {
+ $this->data['data'] .= '</' . end($this->element) . '>';
+ }
+ }
+ if ($this->current_xhtml_construct == -1)
+ {
+ $this->data =& $this->datas[$this->feed];
+ array_pop($this->datas);
+ }
+
+ array_pop($this->element);
+ array_pop($this->namespace);
+ array_pop($this->xml_base);
+ array_pop($this->xml_base_explicit);
+ array_pop($this->xml_lang);
+ $this->feed--;
+ }
+
+ function split_ns($string)
+ {
+ static $cache = array();
+ if (!isset($cache[$string]))
+ {
+ if ($pos = strpos($string, $this->separator))
+ {
+ static $separator_length;
+ if (!$separator_length)
+ {
+ $separator_length = strlen($this->separator);
+ }
+ $namespace = substr($string, 0, $pos);
+ $local_name = substr($string, $pos + $separator_length);
+ if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
+ {
+ $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
+ }
+
+ // Normalize the Media RSS namespaces
+ if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG)
+ {
+ $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
+ }
+ $cache[$string] = array($namespace, $local_name);
+ }
+ else
+ {
+ $cache[$string] = array('', $string);
+ }
+ }
+ return $cache[$string];
+ }
+}
+
+/**
+ * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
+ */
+class SimplePie_Sanitize
+{
+ // Private vars
+ var $base;
+
+ // Options
+ var $remove_div = true;
+ var $image_handler = '';
+ var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+ var $encode_instead_of_strip = false;
+ var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+ var $strip_comments = false;
+ var $output_encoding = 'UTF-8';
+ var $enable_cache = true;
+ var $cache_location = './cache';
+ var $cache_name_function = 'md5';
+ var $cache_class = 'SimplePie_Cache';
+ var $file_class = 'SimplePie_File';
+ var $timeout = 10;
+ var $useragent = '';
+ var $force_fsockopen = false;
+
+ var $replace_url_attributes = array(
+ 'a' => 'href',
+ 'area' => 'href',
+ 'blockquote' => 'cite',
+ 'del' => 'cite',
+ 'form' => 'action',
+ 'img' => array('longdesc', 'src'),
+ 'input' => 'src',
+ 'ins' => 'cite',
+ 'q' => 'cite'
+ );
+
+ function remove_div($enable = true)
+ {
+ $this->remove_div = (bool) $enable;
+ }
+
+ function set_image_handler($page = false)
+ {
+ if ($page)
+ {
+ $this->image_handler = (string) $page;
+ }
+ else
+ {
+ $this->image_handler = false;
+ }
+ }
+
+ function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
+ {
+ if (isset($enable_cache))
+ {
+ $this->enable_cache = (bool) $enable_cache;
+ }
+
+ if ($cache_location)
+ {
+ $this->cache_location = (string) $cache_location;
+ }
+
+ if ($cache_name_function)
+ {
+ $this->cache_name_function = (string) $cache_name_function;
+ }
+
+ if ($cache_class)
+ {
+ $this->cache_class = (string) $cache_class;
+ }
+ }
+
+ function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
+ {
+ if ($file_class)
+ {
+ $this->file_class = (string) $file_class;
+ }
+
+ if ($timeout)
+ {
+ $this->timeout = (string) $timeout;
+ }
+
+ if ($useragent)
+ {
+ $this->useragent = (string) $useragent;
+ }
+
+ if ($force_fsockopen)
+ {
+ $this->force_fsockopen = (string) $force_fsockopen;
+ }
+ }
+
+ function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
+ {
+ if ($tags)
+ {
+ if (is_array($tags))
+ {
+ $this->strip_htmltags = $tags;
+ }
+ else
+ {
+ $this->strip_htmltags = explode(',', $tags);
+ }
+ }
+ else
+ {
+ $this->strip_htmltags = false;
+ }
+ }
+
+ function encode_instead_of_strip($encode = false)
+ {
+ $this->encode_instead_of_strip = (bool) $encode;
+ }
+
+ function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
+ {
+ if ($attribs)
+ {
+ if (is_array($attribs))
+ {
+ $this->strip_attributes = $attribs;
+ }
+ else
+ {
+ $this->strip_attributes = explode(',', $attribs);
+ }
+ }
+ else
+ {
+ $this->strip_attributes = false;
+ }
+ }
+
+ function strip_comments($strip = false)
+ {
+ $this->strip_comments = (bool) $strip;
+ }
+
+ function set_output_encoding($encoding = 'UTF-8')
+ {
+ $this->output_encoding = (string) $encoding;
+ }
+
+ /**
+ * Set element/attribute key/value pairs of HTML attributes
+ * containing URLs that need to be resolved relative to the feed
+ *
+ * @access public
+ * @since 1.0
+ * @param array $element_attribute Element/attribute key/value pairs
+ */
+ function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
+ {
+ $this->replace_url_attributes = (array) $element_attribute;
+ }
+
+ function sanitize($data, $type, $base = '')
+ {
+ $data = trim($data);
+ if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
+ {
+ if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
+ {
+ if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
+ {
+ $type |= SIMPLEPIE_CONSTRUCT_HTML;
+ }
+ else
+ {
+ $type |= SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+ }
+
+ if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
+ {
+ $data = base64_decode($data);
+ }
+
+ if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
+ {
+ if ($this->remove_div)
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
+ $data = preg_replace('/<\/div>$/', '', $data);
+ }
+ else
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
+ }
+ }
+
+ if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
+ {
+ // Strip comments
+ if ($this->strip_comments)
+ {
+ $data = SimplePie_Misc::strip_comments($data);
+ }
+
+ // Strip out HTML tags and attributes that might cause various security problems.
+ // Based on recommendations by Mark Pilgrim at:
+ // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
+ if ($this->strip_htmltags)
+ {
+ foreach ($this->strip_htmltags as $tag)
+ {
+ $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU';
+ while (preg_match($pcre, $data))
+ {
+ $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data);
+ }
+ }
+ }
+
+ if ($this->strip_attributes)
+ {
+ foreach ($this->strip_attributes as $attrib)
+ {
+ $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data);
+ }
+ }
+
+ // Replace relative URLs
+ $this->base = $base;
+ foreach ($this->replace_url_attributes as $element => $attributes)
+ {
+ $data = $this->replace_urls($data, $element, $attributes);
+ }
+
+ // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
+ if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
+ {
+ $images = SimplePie_Misc::get_element('img', $data);
+ foreach ($images as $img)
+ {
+ if (isset($img['attribs']['src']['data']))
+ {
+ $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']);
+ $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi');
+
+ if ($cache->load())
+ {
+ $img['attribs']['src']['data'] = $this->image_handler . $image_url;
+ $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+ }
+ else
+ {
+ $file =& new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
+ $headers = $file->headers;
+
+ if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)))
+ {
+ if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
+ {
+ $img['attribs']['src']['data'] = $this->image_handler . $image_url;
+ $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+ }
+ else
+ {
+ trigger_error("$cache->name is not writeable", E_USER_WARNING);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
+ $data = trim($data);
+ }
+
+ if ($type & SIMPLEPIE_CONSTRUCT_IRI)
+ {
+ $data = SimplePie_Misc::absolutize_url($data, $base);
+ }
+
+ if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
+ {
+ $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
+ }
+
+ if ($this->output_encoding != 'UTF-8')
+ {
+ $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding);
+ }
+ }
+ return $data;
+ }
+
+ function replace_urls($data, $tag, $attributes)
+ {
+ if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
+ {
+ $elements = SimplePie_Misc::get_element($tag, $data);
+ foreach ($elements as $element)
+ {
+ if (is_array($attributes))
+ {
+ foreach ($attributes as $attribute)
+ {
+ if (isset($element['attribs'][$attribute]['data']))
+ {
+ $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
+ $new_element = SimplePie_Misc::element_implode($element);
+ $data = str_replace($element['full'], $new_element, $data);
+ $element['full'] = $new_element;
+ }
+ }
+ }
+ elseif (isset($element['attribs'][$attributes]['data']))
+ {
+ $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
+ $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
+ }
+ }
+ }
+ return $data;
+ }
+
+ function do_strip_htmltags($match)
+ {
+ if ($this->encode_instead_of_strip)
+ {
+ if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+ {
+ $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
+ $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
+ return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
+ }
+ else
+ {
+ return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
+ }
+ }
+ elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+ {
+ return $match[4];
+ }
+ else
+ {
+ return '';
+ }
+ }
+}
+
+?>
diff --git a/src/etc/inc/smtp.inc b/src/etc/inc/smtp.inc
new file mode 100644
index 0000000..035a30a
--- /dev/null
+++ b/src/etc/inc/smtp.inc
@@ -0,0 +1,862 @@
+<?php
+/*
+ * smtp.php
+ *
+ * @(#) $Header$
+ *
+ */
+
+/*
+ pfSense_MODULE: notifications
+*/
+
+class smtp_class
+{
+ var $user="";
+ var $realm="";
+ var $password="";
+ var $workstation="";
+ var $authentication_mechanism="";
+ var $host_name="";
+ var $host_port=25;
+ var $ssl=0;
+ var $tls=0;
+ var $localhost="";
+ var $timeout=0;
+ var $data_timeout=0;
+ var $direct_delivery=0;
+ var $error="";
+ var $debug=0;
+ var $html_debug=0;
+ var $esmtp=1;
+ var $esmtp_host="";
+ var $esmtp_extensions=array();
+ var $maximum_piped_recipients=100;
+ var $exclude_address="";
+ var $getmxrr="GetMXRR";
+ var $pop3_auth_host="";
+ var $pop3_auth_port=110;
+
+ /* private variables - DO NOT ACCESS */
+
+ var $state="Disconnected";
+ var $connection=0;
+ var $pending_recipients=0;
+ var $next_token="";
+ var $direct_sender="";
+ var $connected_domain="";
+ var $result_code;
+ var $disconnected_error=0;
+
+ /* Private methods - DO NOT CALL */
+
+ Function Tokenize($string,$separator="")
+ {
+ if(!strcmp($separator,""))
+ {
+ $separator=$string;
+ $string=$this->next_token;
+ }
+ for($character=0;$character<strlen($separator);$character++)
+ {
+ if(GetType($position=strpos($string,$separator[$character]))=="integer")
+ $found=(IsSet($found) ? min($found,$position) : $position);
+ }
+ if(IsSet($found))
+ {
+ $this->next_token=substr($string,$found+1);
+ return(substr($string,0,$found));
+ }
+ else
+ {
+ $this->next_token="";
+ return($string);
+ }
+ }
+
+ Function OutputDebug($message)
+ {
+ $message.="\n";
+ if($this->html_debug)
+ $message=str_replace("\n","<br />\n",HtmlEntities($message));
+ echo $message;
+ flush();
+ }
+
+ Function SetDataAccessError($error)
+ {
+ $this->error=$error;
+ if(function_exists("socket_get_status"))
+ {
+ $status=socket_get_status($this->connection);
+ if($status["timed_out"])
+ $this->error.=gettext(": data access time out");
+ elseif($status["eof"])
+ {
+ $this->error.=gettext(": the server disconnected");
+ $this->disconnected_error=1;
+ }
+ }
+ }
+
+ Function GetLine()
+ {
+ for($line="";;)
+ {
+ if(feof($this->connection))
+ {
+ $this->error=gettext("reached the end of data while reading from the SMTP server connection");
+ return("");
+ }
+ if(GetType($data=@fgets($this->connection,100))!="string"
+ || strlen($data)==0)
+ {
+ $this->SetDataAccessError(gettext("it was not possible to read line from the SMTP server"));
+ return("");
+ }
+ $line.=$data;
+ $length=strlen($line);
+ if($length>=2
+ && substr($line,$length-2,2)=="\r\n")
+ {
+ $line=substr($line,0,$length-2);
+ if($this->debug)
+ $this->OutputDebug("S $line");
+ return($line);
+ }
+ }
+ }
+
+ Function PutLine($line)
+ {
+ if($this->debug)
+ $this->OutputDebug("C $line");
+ if(!@fputs($this->connection,"$line\r\n"))
+ {
+ $this->SetDataAccessError(gettext("it was not possible to send a line to the SMTP server"));
+ return(0);
+ }
+ return(1);
+ }
+
+ Function PutData(&$data)
+ {
+ if(strlen($data))
+ {
+ if($this->debug)
+ $this->OutputDebug("C $data");
+ if(!@fputs($this->connection,$data))
+ {
+ $this->SetDataAccessError(gettext("it was not possible to send data to the SMTP server"));
+ return(0);
+ }
+ }
+ return(1);
+ }
+
+ Function VerifyResultLines($code,&$responses)
+ {
+ $responses=array();
+ Unset($this->result_code);
+ while(strlen($line=$this->GetLine($this->connection)))
+ {
+ if(IsSet($this->result_code))
+ {
+ if(strcmp($this->Tokenize($line," -"),$this->result_code))
+ {
+ $this->error=$line;
+ return(0);
+ }
+ }
+ else
+ {
+ $this->result_code=$this->Tokenize($line," -");
+ if(GetType($code)=="array")
+ {
+ for($codes=0;$codes<count($code) && strcmp($this->result_code,$code[$codes]);$codes++);
+ if($codes>=count($code))
+ {
+ $this->error=$line;
+ return(0);
+ }
+ }
+ else
+ {
+ if(strcmp($this->result_code,$code))
+ {
+ $this->error=$line;
+ return(0);
+ }
+ }
+ }
+ $responses[]=$this->Tokenize("");
+ if(!strcmp($this->result_code,$this->Tokenize($line," ")))
+ return(1);
+ }
+ return(-1);
+ }
+
+ Function FlushRecipients()
+ {
+ if($this->pending_sender)
+ {
+ if($this->VerifyResultLines("250",$responses)<=0)
+ return(0);
+ $this->pending_sender=0;
+ }
+ for(;$this->pending_recipients;$this->pending_recipients--)
+ {
+ if($this->VerifyResultLines(array("250","251"),$responses)<=0)
+ return(0);
+ }
+ return(1);
+ }
+
+ Function ConnectToHost($domain, $port, $resolve_message)
+ {
+ if($this->ssl || $this->tls)
+ {
+ $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
+ $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
+ if($php_version<4003000)
+ return(gettext("establishing SSL connections requires at least PHP version 4.3.0"));
+ if(!function_exists("extension_loaded")
+ || !extension_loaded("openssl"))
+ return(gettext("establishing SSL connections requires the OpenSSL extension enabled"));
+ }
+ if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
+ $ip=$domain;
+ else
+ {
+ if($this->debug)
+ $this->OutputDebug($resolve_message);
+ if(!strcmp($ip=@gethostbyname($domain),$domain))
+ return(sprintf(gettext("could not resolve host \"%s\""), $domain));
+ }
+ if(strlen($this->exclude_address)
+ && !strcmp(@gethostbyname($this->exclude_address),$ip))
+ return(sprintf(gettext("domain \"%s\" resolved to an address excluded to be valid"), $domain));
+ if($this->debug)
+ $this->OutputDebug(sprintf(gettext('Connecting to host address "%1$s" port %2$s...'), $ip, $port));
+ if(($this->connection=($this->timeout ? @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port,$errno,$error,$this->timeout) : @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port))))
+ return("");
+ $error=($this->timeout ? strval($error) : "??");
+ switch($error)
+ {
+ case "-3":
+ return(gettext("-3 socket could not be created"));
+ case "-4":
+ return(sprintf(gettext("-4 dns lookup on hostname \"%s\" failed"), $domain));
+ case "-5":
+ return(gettext("-5 connection refused or timed out"));
+ case "-6":
+ return(gettext("-6 fdopen() call failed"));
+ case "-7":
+ return(gettext("-7 setvbuf() call failed"));
+ }
+ return(sprintf(gettext('could not connect to the host "%1$s": %2$s'), $domain, $error));
+ }
+
+ Function SASLAuthenticate($mechanisms, $credentials, &$authenticated, &$mechanism)
+ {
+ $authenticated=0;
+ if(!function_exists("class_exists")
+ || !class_exists("sasl_client_class"))
+ {
+ $this->error=gettext("it is not possible to authenticate using the specified mechanism because the SASL library class is not loaded");
+ return(0);
+ }
+ $sasl=new sasl_client_class;
+ $sasl->SetCredential("user",$credentials["user"]);
+ $sasl->SetCredential("password",$credentials["password"]);
+ if(IsSet($credentials["realm"]))
+ $sasl->SetCredential("realm",$credentials["realm"]);
+ if(IsSet($credentials["workstation"]))
+ $sasl->SetCredential("workstation",$credentials["workstation"]);
+ if(IsSet($credentials["mode"]))
+ $sasl->SetCredential("mode",$credentials["mode"]);
+ do
+ {
+ $status=$sasl->Start($mechanisms,$message,$interactions);
+ }
+ while($status==SASL_INTERACT);
+ switch($status)
+ {
+ case SASL_CONTINUE:
+ break;
+ case SASL_NOMECH:
+ if(strlen($this->authentication_mechanism))
+ {
+ $this->error=printf(gettext('authenticated mechanism %1$s may not be used: %2$s'), $this->authentication_mechanism, $sasl->error);
+ return(0);
+ }
+ break;
+ default:
+ $this->error=gettext("Could not start the SASL authentication client:") . " ".$sasl->error;
+ return(0);
+ }
+ if(strlen($mechanism=$sasl->mechanism))
+ {
+ if($this->PutLine("AUTH ".$sasl->mechanism.(IsSet($message) ? " ".base64_encode($message) : ""))==0)
+ {
+ $this->error=gettext("Could not send the AUTH command");
+ return(0);
+ }
+ if(!$this->VerifyResultLines(array("235","334"),$responses))
+ return(0);
+ switch($this->result_code)
+ {
+ case "235":
+ $response="";
+ $authenticated=1;
+ break;
+ case "334":
+ $response=base64_decode($responses[0]);
+ break;
+ default:
+ $this->error=gettext("Authentication error:") . " ".$responses[0];
+ return(0);
+ }
+ for(;!$authenticated;)
+ {
+ do
+ {
+ $status=$sasl->Step($response,$message,$interactions);
+ }
+ while($status==SASL_INTERACT);
+ switch($status)
+ {
+ case SASL_CONTINUE:
+ if($this->PutLine(base64_encode($message))==0)
+ {
+ $this->error=gettext("Could not send the authentication step message");
+ return(0);
+ }
+ if(!$this->VerifyResultLines(array("235","334"),$responses))
+ return(0);
+ switch($this->result_code)
+ {
+ case "235":
+ $response="";
+ $authenticated=1;
+ break;
+ case "334":
+ $response=base64_decode($responses[0]);
+ break;
+ default:
+ $this->error=gettext("Authentication error:") . " ".$responses[0];
+ return(0);
+ }
+ break;
+ default:
+ $this->error=gettext("Could not process the SASL authentication step:") . " ".$sasl->error;
+ return(0);
+ }
+ }
+ }
+ return(1);
+ }
+
+ /* Public methods */
+
+ Function Connect($domain="")
+ {
+ if(strcmp($this->state,"Disconnected"))
+ {
+ $this->error=gettext("connection is already established");
+ return(0);
+ }
+ $this->disconnected_error=0;
+ $this->error=$error="";
+ $this->esmtp_host="";
+ $this->esmtp_extensions=array();
+ $hosts=array();
+ if($this->direct_delivery)
+ {
+ if(strlen($domain)==0)
+ return(1);
+ $hosts=$weights=$mxhosts=array();
+ $getmxrr=$this->getmxrr;
+ if(function_exists($getmxrr)
+ && $getmxrr($domain,$hosts,$weights))
+ {
+ for($host=0;$host<count($hosts);$host++)
+ $mxhosts[$weights[$host]]=$hosts[$host];
+ KSort($mxhosts);
+ for(Reset($mxhosts),$host=0;$host<count($mxhosts);Next($mxhosts),$host++)
+ $hosts[$host]=$mxhosts[Key($mxhosts)];
+ }
+ else
+ {
+ if(strcmp(@gethostbyname($domain),$domain)!=0)
+ $hosts[]=$domain;
+ }
+ }
+ else
+ {
+ if(strlen($this->host_name))
+ $hosts[]=$this->host_name;
+ if(strlen($this->pop3_auth_host))
+ {
+ $user=$this->user;
+ if(strlen($user)==0)
+ {
+ $this->error=gettext("it was not specified the POP3 authentication user");
+ return(0);
+ }
+ $password=$this->password;
+ if(strlen($password)==0)
+ {
+ $this->error=gettext("it was not specified the POP3 authentication password");
+ return(0);
+ }
+ $domain=$this->pop3_auth_host;
+ $this->error=$this->ConnectToHost($domain, $this->pop3_auth_port, sprintf(gettext("Resolving POP3 authentication host \"%s\"..."), $domain));
+ if(strlen($this->error))
+ return(0);
+ if(strlen($response=$this->GetLine())==0)
+ return(0);
+ if(strcmp($this->Tokenize($response," "),"+OK"))
+ {
+ $this->error=gettext("POP3 authentication server greeting was not found");
+ return(0);
+ }
+ if(!$this->PutLine("USER ".$this->user)
+ || strlen($response=$this->GetLine())==0)
+ return(0);
+ if(strcmp($this->Tokenize($response," "),"+OK"))
+ {
+ $this->error=gettext("POP3 authentication user was not accepted:") . " ".$this->Tokenize("\r\n");
+ return(0);
+ }
+ if(!$this->PutLine("PASS ".$password)
+ || strlen($response=$this->GetLine())==0)
+ return(0);
+ if(strcmp($this->Tokenize($response," "),"+OK"))
+ {
+ $this->error=gettext("POP3 authentication password was not accepted:") . " ".$this->Tokenize("\r\n");
+ return(0);
+ }
+ fclose($this->connection);
+ $this->connection=0;
+ }
+ }
+ if(count($hosts)==0)
+ {
+ $this->error=gettext("could not determine the SMTP to connect");
+ return(0);
+ }
+ for($host=0, $error="not connected";strlen($error) && $host<count($hosts);$host++)
+ {
+ $domain=$hosts[$host];
+ $error=$this->ConnectToHost($domain, $this->host_port, sprintf(gettext("Resolving SMTP server domain \"%s\"..."), $domain));
+ }
+ if(strlen($error))
+ {
+ $this->error=$error;
+ return(0);
+ }
+ $timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
+ if($timeout
+ && function_exists("socket_set_timeout"))
+ socket_set_timeout($this->connection,$timeout,0);
+ if($this->debug)
+ $this->OutputDebug(sprintf(gettext("Connected to SMTP server \"%s\"."), $domain));
+ if($this->VerifyResultLines("220",$responses)>0)
+ {
+ // Send our HELLO
+ $success = $this->hello($this->hostname());
+ if ($this->tls)
+ $success = $this->startTLS();
+
+ if($success
+ && strlen($this->user)
+ && strlen($this->pop3_auth_host)==0)
+ {
+ if(!IsSet($this->esmtp_extensions["AUTH"]))
+ {
+ $this->error = gettext("server does not require authentication");
+ $success=0;
+ }
+ else
+ {
+ if(strlen($this->authentication_mechanism))
+ $mechanisms=array($this->authentication_mechanism);
+ else
+ {
+ $mechanisms=array();
+ for($authentication=$this->Tokenize($this->esmtp_extensions["AUTH"]," ");strlen($authentication);$authentication=$this->Tokenize(" "))
+ $mechanisms[]=$authentication;
+ }
+ $credentials=array(
+ "user"=>$this->user,
+ "password"=>$this->password
+ );
+ if(strlen($this->realm))
+ $credentials["realm"]=$this->realm;
+ if(strlen($this->workstation))
+ $credentials["workstation"]=$this->workstation;
+ $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
+ if(!$success
+ && !strcmp($mechanism,"PLAIN"))
+ {
+ /*
+ * Author: Russell Robinson, 25 May 2003, http://www.tectite.com/
+ * Purpose: Try various AUTH PLAIN authentication methods.
+ */
+ $mechanisms=array("PLAIN");
+ $credentials=array(
+ "user"=>$this->user,
+ "password"=>$this->password
+ );
+ if(strlen($this->realm))
+ {
+ /*
+ * According to: http://www.sendmail.org/~ca/email/authrealms.html#authpwcheck_method
+ * some sendmails won't accept the realm, so try again without it
+ */
+ $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
+ }
+ if(!$success)
+ {
+ /*
+ * It was seen an EXIM configuration like this:
+ * user^password^unused
+ */
+ $credentials["mode"]=SASL_PLAIN_EXIM_DOCUMENTATION_MODE;
+ $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
+ }
+ if(!$success)
+ {
+ /*
+ * ... though: http://exim.work.de/exim-html-3.20/doc/html/spec_36.html
+ * specifies: ^user^password
+ */
+ $credentials["mode"]=SASL_PLAIN_EXIM_MODE;
+ $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
+ }
+ }
+ if($success
+ && strlen($mechanism)==0)
+ {
+ $this->error=gettext("it is not supported any of the authentication mechanisms required by the server");
+ $success=0;
+ }
+ }
+ }
+ }
+ if($success)
+ {
+ $this->state="Connected";
+ $this->connected_domain=$domain;
+ }
+ else
+ {
+ fclose($this->connection);
+ $this->connection=0;
+ }
+ return($success);
+ }
+
+ Function hostname() {
+ if(!strcmp($localhost=$this->localhost,"")
+ && !strcmp($localhost=getenv("SERVER_NAME"),"")
+ && !strcmp($localhost=getenv("HOST"),"")
+ && !strcmp($localhost=getenv("HOSTNAME"),"")
+ && !strcmp($localhost=gethostname(),""))
+ $localhost="localhost";
+
+ return $localhost;
+ }
+
+ Function hello()
+ {
+ $success = 0;
+ $fallback = 1;
+ if ($this->esmtp || strlen($this->user)) {
+ if ($this->PutLine("EHLO ".$this->hostname())) {
+ if (($success_code = $this->VerifyResultLines("250",$responses)) > 0) {
+ $this->esmtp_host = $this->Tokenize($responses[0]," ");
+ for($response=1;$response<count($responses);$response++) {
+ $extension = strtoupper($this->Tokenize($responses[$response]," "));
+ $this->esmtp_extensions[$extension]=$this->Tokenize("");
+ }
+ $success = 1;
+ $fallback = 0;
+ } else {
+ if ($success_code == 0) {
+ $code = $this->Tokenize($this->error," -");
+ switch($code) {
+ case "421":
+ $fallback=0;
+ break;
+ }
+ }
+ }
+ } else
+ $fallback=0;
+ }
+
+ if ($fallback) {
+ if ($this->PutLine("HELO $localhost") && $this->VerifyResultLines("250",$responses)>0)
+ $success=1;
+ }
+ return $success;
+ }
+
+ Function startTLS() {
+ if ($this->PutLine("STARTTLS") && $this->VerifyResultLines("220",$responses)>0) {
+ if (!stream_socket_enable_crypto($this->connection,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
+ return false;
+ } else {
+ // Resend HELO since session has been reset
+ return $this->hello($this->hostname);
+ }
+ } else
+ return false;
+ }
+
+ Function MailFrom($sender)
+ {
+ if($this->direct_delivery)
+ {
+ switch($this->state)
+ {
+ case "Disconnected":
+ $this->direct_sender=$sender;
+ return(1);
+ case "Connected":
+ $sender=$this->direct_sender;
+ break;
+ default:
+ $this->error=gettext("direct delivery connection is already established and sender is already set");
+ return(0);
+ }
+ }
+ else
+ {
+ if(strcmp($this->state,"Connected"))
+ {
+ $this->error=gettext("connection is not in the initial state");
+ return(0);
+ }
+ }
+ $this->error="";
+ if(!$this->PutLine("MAIL FROM:<$sender>"))
+ return(0);
+ if(!IsSet($this->esmtp_extensions["PIPELINING"])
+ && $this->VerifyResultLines("250",$responses)<=0)
+ return(0);
+ $this->state="SenderSet";
+ if(IsSet($this->esmtp_extensions["PIPELINING"]))
+ $this->pending_sender=1;
+ $this->pending_recipients=0;
+ return(1);
+ }
+
+ Function SetRecipient($recipient)
+ {
+ if($this->direct_delivery)
+ {
+ if(GetType($at=strrpos($recipient,"@"))!="integer")
+ return(gettext("it was not specified a valid direct recipient"));
+ $domain=substr($recipient,$at+1);
+ switch($this->state)
+ {
+ case "Disconnected":
+ if(!$this->Connect($domain))
+ return(0);
+ if(!$this->MailFrom(""))
+ {
+ $error=$this->error;
+ $this->Disconnect();
+ $this->error=$error;
+ return(0);
+ }
+ break;
+ case "SenderSet":
+ case "RecipientSet":
+ if(strcmp($this->connected_domain,$domain))
+ {
+ $this->error=gettext("it is not possible to deliver directly to recipients of different domains");
+ return(0);
+ }
+ break;
+ default:
+ $this->error=gettext("connection is already established and the recipient is already set");
+ return(0);
+ }
+ }
+ else
+ {
+ switch($this->state)
+ {
+ case "SenderSet":
+ case "RecipientSet":
+ break;
+ default:
+ $this->error=gettext("connection is not in the recipient setting state");
+ return(0);
+ }
+ }
+ $this->error="";
+ if(!$this->PutLine("RCPT TO:<$recipient>"))
+ return(0);
+ if(IsSet($this->esmtp_extensions["PIPELINING"]))
+ {
+ $this->pending_recipients++;
+ if($this->pending_recipients>=$this->maximum_piped_recipients)
+ {
+ if(!$this->FlushRecipients())
+ return(0);
+ }
+ }
+ else
+ {
+ if($this->VerifyResultLines(array("250","251"),$responses)<=0)
+ return(0);
+ }
+ $this->state="RecipientSet";
+ return(1);
+ }
+
+ Function StartData()
+ {
+ if(strcmp($this->state,"RecipientSet"))
+ {
+ $this->error=gettext("connection is not in the start sending data state");
+ return(0);
+ }
+ $this->error="";
+ if(!$this->PutLine("DATA"))
+ return(0);
+ if($this->pending_recipients)
+ {
+ if(!$this->FlushRecipients())
+ return(0);
+ }
+ if($this->VerifyResultLines("354",$responses)<=0)
+ return(0);
+ $this->state="SendingData";
+ return(1);
+ }
+
+ Function PrepareData(&$data,&$output,$preg=1)
+ {
+ if($preg
+ && function_exists("preg_replace"))
+ $output=preg_replace(array("/\n\n|\r\r/","/(^|[^\r])\n/","/\r([^\n]|\$)/D","/(^|\n)\\./"),array("\r\n\r\n","\\1\r\n","\r\n\\1","\\1.."),$data);
+ else
+ $output=ereg_replace("(^|\n)\\.","\\1..",ereg_replace("\r([^\n]|\$)","\r\n\\1",ereg_replace("(^|[^\r])\n","\\1\r\n",ereg_replace("\n\n|\r\r","\r\n\r\n",$data))));
+ }
+
+ Function SendData($data)
+ {
+ if(strcmp($this->state,"SendingData"))
+ {
+ $this->error=gettext("connection is not in the sending data state");
+ return(0);
+ }
+ $this->error="";
+ return($this->PutData($data));
+ }
+
+ Function EndSendingData()
+ {
+ if(strcmp($this->state,"SendingData"))
+ {
+ $this->error=gettext("connection is not in the sending data state");
+ return(0);
+ }
+ $this->error="";
+ if(!$this->PutLine("\r\n.")
+ || $this->VerifyResultLines("250",$responses)<=0)
+ return(0);
+ $this->state="Connected";
+ return(1);
+ }
+
+ Function ResetConnection()
+ {
+ switch($this->state)
+ {
+ case "Connected":
+ return(1);
+ case "SendingData":
+ $this->error="can not reset the connection while sending data";
+ return(0);
+ case "Disconnected":
+ $this->error="can not reset the connection before it is established";
+ return(0);
+ }
+ $this->error="";
+ if(!$this->PutLine("RSET")
+ || $this->VerifyResultLines("250",$responses)<=0)
+ return(0);
+ $this->state="Connected";
+ return(1);
+ }
+
+ Function Disconnect($quit=1)
+ {
+ if(!strcmp($this->state,"Disconnected"))
+ {
+ $this->error=gettext("it was not previously established a SMTP connection");
+ return(0);
+ }
+ $this->error="";
+ if(!strcmp($this->state,"Connected")
+ && $quit
+ && (!$this->PutLine("QUIT")
+ || ($this->VerifyResultLines("221",$responses)<=0
+ && !$this->disconnected_error)))
+ return(0);
+ if($this->disconnected_error)
+ $this->disconnected_error=0;
+ else
+ fclose($this->connection);
+ $this->connection=0;
+ $this->state="Disconnected";
+ if($this->debug)
+ $this->OutputDebug("Disconnected.");
+ return(1);
+ }
+
+ Function SendMessage($sender,$recipients,$headers,$body)
+ {
+ if(($success=$this->Connect()))
+ {
+ if(($success=$this->MailFrom($sender)))
+ {
+ for($recipient=0;$recipient<count($recipients);$recipient++)
+ {
+ if(!($success=$this->SetRecipient($recipients[$recipient])))
+ break;
+ }
+ if($success
+ && ($success=$this->StartData()))
+ {
+ for($header_data="",$header=0;$header<count($headers);$header++)
+ $header_data.=$headers[$header]."\r\n";
+ if(($success=$this->SendData($header_data."\r\n")))
+ {
+ $this->PrepareData($body,$body_data);
+ $success=$this->SendData($body_data);
+ }
+ if($success)
+ $success=$this->EndSendingData();
+ }
+ }
+ $error=$this->error;
+ $disconnect_success=$this->Disconnect($success);
+ if($success)
+ $success=$disconnect_success;
+ else
+ $this->error=$error;
+ }
+ return($success);
+ }
+
+};
+
+?>
diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
new file mode 100644
index 0000000..41e798e
--- /dev/null
+++ b/src/etc/inc/system.inc
@@ -0,0 +1,2258 @@
+<?php
+/* $Id$ */
+/*
+ system.inc
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/sbin/powerd /usr/bin/killall /sbin/route
+ pfSense_BUILDER_BINARIES: /bin/hostname /bin/ls /usr/sbin/syslogd
+ pfSense_BUILDER_BINARIES: /usr/sbin/pccardd /usr/local/sbin/lighttpd /bin/chmod /bin/mkdir
+ pfSense_BUILDER_BINARIES: /usr/bin/tar /usr/local/sbin/ntpd /usr/local/sbin/ntpdate
+ pfSense_BUILDER_BINARIES: /usr/bin/nohup /sbin/dmesg /usr/local/sbin/atareinit /sbin/kldload
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/filterdns
+ pfSense_MODULE: utils
+*/
+
+function activate_powerd() {
+ global $config, $g;
+
+ if (is_process_running("powerd")) {
+ exec("/usr/bin/killall powerd");
+ }
+ if (isset($config['system']['powerd_enable'])) {
+ if ($g["platform"] == "nanobsd") {
+ exec("/sbin/kldload cpufreq");
+ }
+
+ $ac_mode = "hadp";
+ if (!empty($config['system']['powerd_ac_mode'])) {
+ $ac_mode = $config['system']['powerd_ac_mode'];
+ }
+
+ $battery_mode = "hadp";
+ if (!empty($config['system']['powerd_battery_mode'])) {
+ $battery_mode = $config['system']['powerd_battery_mode'];
+ }
+
+ $normal_mode = "hadp";
+ if (!empty($config['system']['powerd_normal_mode'])) {
+ $normal_mode = $config['system']['powerd_normal_mode'];
+ }
+
+ mwexec("/usr/sbin/powerd -b $battery_mode -a $ac_mode -n $normal_mode");
+ }
+}
+
+function get_default_sysctl_value($id) {
+ global $sysctls;
+
+ if (isset($sysctls[$id])) {
+ return $sysctls[$id];
+ }
+}
+
+function get_sysctl_descr($sysctl) {
+ unset($output);
+ $_gb = exec("/sbin/sysctl -nd {$sysctl}", $output);
+
+ return $output[0];
+}
+
+function system_get_sysctls() {
+ global $config, $sysctls;
+
+ $disp_sysctl = array();
+ $disp_cache = array();
+ if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
+ foreach ($config['sysctl']['item'] as $id => $tunable) {
+ if ($tunable['value'] == "default") {
+ $value = get_default_sysctl_value($tunable['tunable']);
+ } else {
+ $value = $tunable['value'];
+ }
+
+ $disp_sysctl[$id] = $tunable;
+ $disp_sysctl[$id]['modified'] = true;
+ $disp_cache[$tunable['tunable']] = 'set';
+ }
+ }
+
+ foreach ($sysctls as $sysctl => $value) {
+ if (isset($disp_cache[$sysctl])) {
+ continue;
+ }
+
+ $disp_sysctl[$sysctl] = array('tunable' => $sysctl, 'value' => $value, 'descr' => get_sysctl_descr($sysctl));
+ }
+ unset($disp_cache);
+ return $disp_sysctl;
+}
+
+function activate_sysctls() {
+ global $config, $g, $sysctls;
+
+ if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
+ foreach ($config['sysctl']['item'] as $tunable) {
+ if ($tunable['value'] == "default") {
+ $value = get_default_sysctl_value($tunable['tunable']);
+ } else {
+ $value = $tunable['value'];
+ }
+
+ $sysctls[$tunable['tunable']] = $value;
+ }
+ }
+
+ set_sysctl($sysctls);
+}
+
+function system_resolvconf_generate($dynupdate = false) {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_resolvconf_generate() being called $mt\n";
+ }
+
+ $syscfg = $config['system'];
+
+ if ((((isset($config['dnsmasq']['enable'])) &&
+ (!isset($config['dnsmasq']['port']) || $config['dnsmasq']['port'] == "53") &&
+ (empty($config['dnsmasq']['interface']) ||
+ in_array("lo0", explode(",", $config['dnsmasq']['interface'])))) ||
+ ((isset($config['unbound']['enable'])) &&
+ (!isset($config['unbound']['port']) || $config['unbound']['port'] == "53") &&
+ (empty($config['unbound']['active_interface']) ||
+ in_array("lo0", explode(",", $config['unbound']['active_interface'])) ||
+ in_array("all", explode(",", $config['unbound']['active_interface']), true)))) &&
+ (!isset($config['system']['dnslocalhost']))) {
+ $resolvconf .= "nameserver 127.0.0.1\n";
+ }
+
+ if (isset($syscfg['dnsallowoverride'])) {
+ /* get dynamically assigned DNS servers (if any) */
+ $ns = array_unique(get_searchdomains());
+ foreach ($ns as $searchserver) {
+ if ($searchserver) {
+ $resolvconf .= "search {$searchserver}\n";
+ }
+ }
+ $ns = array_unique(get_nameservers());
+ foreach ($ns as $nameserver) {
+ if ($nameserver) {
+ $resolvconf .= "nameserver $nameserver\n";
+ }
+ }
+ } else {
+ $ns = array();
+ // Do not create blank search/domain lines, it can break tools like dig.
+ if ($syscfg['domain']) {
+ $resolvconf .= "search {$syscfg['domain']}\n";
+ }
+ }
+ if (is_array($syscfg['dnsserver'])) {
+ foreach ($syscfg['dnsserver'] as $sys_dnsserver) {
+ if ($sys_dnsserver && (!in_array($sys_dnsserver, $ns))) {
+ $resolvconf .= "nameserver $sys_dnsserver\n";
+ }
+ }
+ }
+
+ // Add EDNS support
+ if (isset($config['unbound']['enable']) && isset($config['unbound']['edns'])) {
+ $resolvconf .= "options edns0\n";
+ }
+
+ $dnslock = lock('resolvconf', LOCK_EX);
+
+ $fd = fopen("{$g['varetc_path']}/resolv.conf", "w");
+ if (!$fd) {
+ printf("Error: cannot open resolv.conf in system_resolvconf_generate().\n");
+ unlock($dnslock);
+ return 1;
+ }
+
+ fwrite($fd, $resolvconf);
+ fclose($fd);
+
+ // Prevent resolvconf(8) from rewriting our resolv.conf
+ $fd = fopen("{$g['varetc_path']}/resolvconf.conf", "w");
+ if (!$fd) {
+ printf("Error: cannot open resolvconf.conf in system_resolvconf_generate().\n");
+ return 1;
+ }
+ fwrite($fd, "resolv_conf=\"/dev/null\"\n");
+ fclose($fd);
+
+ if (!platform_booting()) {
+ /* restart dhcpd (nameservers may have changed) */
+ if (!$dynupdate) {
+ services_dhcpd_configure();
+ }
+ }
+
+ /* setup static routes for DNS servers. */
+ for ($dnscounter=1; $dnscounter<5; $dnscounter++) {
+ /* setup static routes for dns servers */
+ $dnsgw = "dns{$dnscounter}gw";
+ if (isset($config['system'][$dnsgw])) {
+ $gwname = $config['system'][$dnsgw];
+ if (($gwname <> "") && ($gwname <> "none")) {
+ $gatewayip = lookup_gateway_ip_by_name($gwname);
+ if (is_ipaddrv4($gatewayip)) {
+ /* dns server array starts at 0 */
+ $dnscountermo = $dnscounter - 1;
+ mwexec("/sbin/route change -host " . $syscfg['dnsserver'][$dnscountermo] . " {$gatewayip}");
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - route change -host {$syscfg['dnsserver'][$dnscountermo]} $gatewayip ");
+ }
+ }
+ if (is_ipaddrv6($gatewayip)) {
+ /* dns server array starts at 0 */
+ $dnscountermo = $dnscounter - 1;
+ mwexec("/sbin/route change -host -inet6 " . $syscfg['dnsserver'][$dnscountermo] . " {$gatewayip}");
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - route change -host -inet6 {$syscfg['dnsserver'][$dnscountermo]} $gatewayip ");
+ }
+ }
+ }
+ }
+ }
+
+ unlock($dnslock);
+
+ return 0;
+}
+
+function get_searchdomains() {
+ global $config, $g;
+
+ $master_list = array();
+
+ // Read in dhclient nameservers
+ $search_list = glob("/var/etc/searchdomain_*");
+ if (is_array($search_list)) {
+ foreach ($search_list as $fdns) {
+ $contents = file($fdns, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!is_array($contents)) {
+ continue;
+ }
+ foreach ($contents as $dns) {
+ if (is_hostname($dns)) {
+ $master_list[] = $dns;
+ }
+ }
+ }
+ }
+
+ return $master_list;
+}
+
+function get_nameservers() {
+ global $config, $g;
+ $master_list = array();
+
+ // Read in dhclient nameservers
+ $dns_lists = glob("/var/etc/nameserver_*");
+ if (is_array($dns_lists)) {
+ foreach ($dns_lists as $fdns) {
+ $contents = file($fdns, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!is_array($contents)) {
+ continue;
+ }
+ foreach ($contents as $dns) {
+ if (is_ipaddr($dns)) {
+ $master_list[] = $dns;
+ }
+ }
+ }
+ }
+
+ // Read in any extra nameservers
+ if (file_exists("/var/etc/nameservers.conf")) {
+ $dns_s = file("/var/etc/nameservers.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (is_array($dns_s)) {
+ foreach ($dns_s as $dns) {
+ if (is_ipaddr($dns)) {
+ $master_list[] = $dns;
+ }
+ }
+ }
+ }
+
+ return $master_list;
+}
+
+function system_hosts_generate() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_hosts_generate() being called $mt\n";
+ }
+
+ $syscfg = $config['system'];
+ if (isset($config['unbound']) && isset($config['unbound']['enable'])) {
+ $dnsmasqcfg = $config['unbound'];
+ } else {
+ $dnsmasqcfg = $config['dnsmasq'];
+ }
+
+ $hosts = "127.0.0.1 localhost localhost.{$syscfg['domain']}\n";
+ $hosts .= "::1 localhost localhost.{$syscfg['domain']}\n";
+ $lhosts = "";
+ $dhosts = "";
+
+ if ($config['interfaces']['lan']) {
+ $cfgip = get_interface_ip("lan");
+ if (is_ipaddr($cfgip)) {
+ $hosts .= "{$cfgip} {$syscfg['hostname']}.{$syscfg['domain']} {$syscfg['hostname']}\n";
+ }
+ $cfgipv6 = get_interface_ipv6("lan");
+ if (is_ipaddrv6($cfgipv6)) {
+ $hosts .= "{$cfgipv6} {$syscfg['hostname']}.{$syscfg['domain']} {$syscfg['hostname']}\n";
+ }
+ } else {
+ $sysiflist = get_configured_interface_list();
+ $hosts_if_found = false;
+ foreach ($sysiflist as $sysif) {
+ if (!interface_has_gateway($sysif)) {
+ $cfgip = get_interface_ip($sysif);
+ if (is_ipaddr($cfgip)) {
+ $hosts .= "{$cfgip} {$syscfg['hostname']}.{$syscfg['domain']} {$syscfg['hostname']}\n";
+ $hosts_if_found = true;
+ }
+ $cfgipv6 = get_interface_ipv6($sysif);
+ if (is_ipaddrv6($cfgipv6)) {
+ $hosts .= "{$cfgipv6} {$syscfg['hostname']}.{$syscfg['domain']} {$syscfg['hostname']}\n";
+ $hosts_if_found = true;
+ }
+ if ($hosts_if_found == true) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (isset($dnsmasqcfg['enable'])) {
+ if (!is_array($dnsmasqcfg['hosts'])) {
+ $dnsmasqcfg['hosts'] = array();
+ }
+
+ foreach ($dnsmasqcfg['hosts'] as $host) {
+ if ($host['host'] || $host['host'] == "0") {
+ $lhosts .= "{$host['ip']} {$host['host']}.{$host['domain']} {$host['host']}\n";
+ } else {
+ $lhosts .= "{$host['ip']} {$host['domain']}\n";
+ }
+ if (!is_array($host['aliases']) || !is_array($host['aliases']['item'])) {
+ continue;
+ }
+ foreach ($host['aliases']['item'] as $alias) {
+ if ($alias['host'] || $alias['host'] == "0") {
+ $lhosts .= "{$host['ip']} {$alias['host']}.{$alias['domain']} {$alias['host']}\n";
+ } else {
+ $lhosts .= "{$host['ip']} {$alias['domain']}\n";
+ }
+ }
+ }
+ if (isset($dnsmasqcfg['regdhcpstatic']) && is_array($config['dhcpd'])) {
+ foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
+ if (is_array($dhcpifconf['staticmap']) && isset($dhcpifconf['enable'])) {
+ foreach ($dhcpifconf['staticmap'] as $host) {
+ if ($host['ipaddr'] && $host['hostname'] && $host['domain']) {
+ $dhosts .= "{$host['ipaddr']} {$host['hostname']}.{$host['domain']} {$host['hostname']}\n";
+ } else if ($host['ipaddr'] && $host['hostname'] && $dhcpifconf['domain']) {
+ $dhosts .= "{$host['ipaddr']} {$host['hostname']}.{$dhcpifconf['domain']} {$host['hostname']}\n";
+ } else if ($host['ipaddr'] && $host['hostname']) {
+ $dhosts .= "{$host['ipaddr']} {$host['hostname']}.{$syscfg['domain']} {$host['hostname']}\n";
+ }
+ }
+ }
+ }
+ }
+ if (isset($dnsmasqcfg['regdhcpstatic']) && is_array($config['dhcpdv6'])) {
+ foreach ($config['dhcpdv6'] as $dhcpif => $dhcpifconf) {
+ if (is_array($dhcpifconf['staticmap']) && isset($dhcpifconf['enable'])) {
+ foreach ($dhcpifconf['staticmap'] as $host) {
+ if ($host['ipaddrv6'] && $host['hostname'] && $host['domain']) {
+ $dhosts .= "{$host['ipaddrv6']} {$host['hostname']}.{$host['domain']} {$host['hostname']}\n";
+ } else if ($host['ipaddrv6'] && $host['hostname'] && $dhcpifconf['domain']) {
+ $dhosts .= "{$host['ipaddrv6']} {$host['hostname']}.{$dhcpifconf['domain']} {$host['hostname']}\n";
+ } else if ($host['ipaddrv6'] && $host['hostname']) {
+ $dhosts .= "{$host['ipaddrv6']} {$host['hostname']}.{$syscfg['domain']} {$host['hostname']}\n";
+ }
+ }
+ }
+ }
+ }
+
+ if (isset($dnsmasqcfg['dhcpfirst'])) {
+ $hosts .= $dhosts . $lhosts;
+ } else {
+ $hosts .= $lhosts . $dhosts;
+ }
+ }
+
+ /*
+ * Do not remove this because dhcpleases monitors with kqueue it needs to be
+ * killed before writing to hosts files.
+ */
+ if (file_exists("{$g['varrun_path']}/dhcpleases.pid")) {
+ sigkillbypid("{$g['varrun_path']}/dhcpleases.pid", "TERM");
+ @unlink("{$g['varrun_path']}/dhcpleases.pid");
+ }
+ $fd = fopen("{$g['varetc_path']}/hosts", "w");
+ if (!$fd) {
+ log_error("Error: cannot open hosts file in system_hosts_generate().\n");
+ return 1;
+ }
+ fwrite($fd, $hosts);
+ fclose($fd);
+
+ if (isset($config['unbound']['enable'])) {
+ require_once("unbound.inc");
+ unbound_hosts_generate();
+ }
+
+ return 0;
+}
+
+function system_dhcpleases_configure() {
+ global $config, $g;
+
+ /* Start the monitoring process for dynamic dhcpclients. */
+ if ((isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcp'])) ||
+ (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcp']))) {
+ /* Make sure we do not error out */
+ mwexec("/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db");
+ if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
+ @touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
+ }
+
+ if (isset($config['unbound']['enable'])) {
+ $dns_pid = "unbound.pid";
+ $unbound_conf = "-u {$g['unbound_chroot_path']}/dhcpleases_entries.conf";
+ } else {
+ $dns_pid = "dnsmasq.pid";
+ $unbound_conf = "";
+ }
+
+ $pidfile = "{$g['varrun_path']}/dhcpleases.pid";
+ if (isvalidpid($pidfile)) {
+ /* Make sure dhcpleases is using correct unbound or dnsmasq */
+ $_gb = exec("/bin/pgrep -F {$pidfile} -f {$dns_pid}", $output, $retval);
+ if (intval($retval) == 0) {
+ sigkillbypid($pidfile, "HUP");
+ return;
+ } else {
+ sigkillbypid($pidfile, "TERM");
+ }
+ }
+
+ /* To ensure we do not start multiple instances of dhcpleases, perform some clean-up first. */
+ if (is_process_running("dhcpleases")) {
+ sigkillbyname('dhcpleases', "TERM");
+ }
+ @unlink($pidfile);
+ mwexec("/usr/local/sbin/dhcpleases -l {$g['dhcpd_chroot_path']}/var/db/dhcpd.leases -d {$config['system']['domain']} -p {$g['varrun_path']}/{$dns_pid} {$unbound_conf} -h {$g['varetc_path']}/hosts");
+ } else {
+ sigkillbypid($pidfile, "TERM");
+ @unlink($pidfile);
+ }
+}
+
+function system_hostname_configure() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_hostname_configure() being called $mt\n";
+ }
+
+ $syscfg = $config['system'];
+
+ /* set hostname */
+ $status = mwexec("/bin/hostname " .
+ escapeshellarg("{$syscfg['hostname']}.{$syscfg['domain']}"));
+
+ /* Setup host GUID ID. This is used by ZFS. */
+ mwexec("/etc/rc.d/hostid start");
+
+ return $status;
+}
+
+function system_routing_configure($interface = "") {
+ global $config, $g;
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_routing_configure() being called $mt\n";
+ }
+
+ $gatewayip = "";
+ $interfacegw = "";
+ $gatewayipv6 = "";
+ $interfacegwv6 = "";
+ $foundgw = false;
+ $foundgwv6 = false;
+ /* tack on all the hard defined gateways as well */
+ if (is_array($config['gateways']['gateway_item'])) {
+ array_map('unlink', glob("{$g['tmp_path']}/*_defaultgw{,v6}", GLOB_BRACE));
+ foreach ($config['gateways']['gateway_item'] as $gateway) {
+ if (isset($gateway['defaultgw'])) {
+ if ($foundgw == false && ($gateway['ipprotocol'] != "inet6" && (is_ipaddrv4($gateway['gateway']) || $gateway['gateway'] == "dynamic"))) {
+ if (strpos($gateway['gateway'], ":")) {
+ continue;
+ }
+ if ($gateway['gateway'] == "dynamic") {
+ $gateway['gateway'] = get_interface_gateway($gateway['interface']);
+ }
+ $gatewayip = $gateway['gateway'];
+ $interfacegw = $gateway['interface'];
+ if (!empty($gateway['interface'])) {
+ $defaultif = get_real_interface($gateway['interface']);
+ if ($defaultif) {
+ @file_put_contents("{$g['tmp_path']}/{$defaultif}_defaultgw", $gateway['gateway']);
+ }
+ }
+ $foundgw = true;
+ } else if ($foundgwv6 == false && ($gateway['ipprotocol'] == "inet6" && (is_ipaddrv6($gateway['gateway']) || $gateway['gateway'] == "dynamic"))) {
+ if ($gateway['gateway'] == "dynamic") {
+ $gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
+ }
+ $gatewayipv6 = $gateway['gateway'];
+ $interfacegwv6 = $gateway['interface'];
+ if (!empty($gateway['interface'])) {
+ $defaultifv6 = get_real_interface($gateway['interface']);
+ if ($defaultifv6) {
+ @file_put_contents("{$g['tmp_path']}/{$defaultifv6}_defaultgwv6", $gateway['gateway']);
+ }
+ }
+ $foundgwv6 = true;
+ }
+ }
+ if ($foundgw === true && $foundgwv6 === true) {
+ break;
+ }
+ }
+ }
+ if ($foundgw == false) {
+ $defaultif = get_real_interface("wan");
+ $interfacegw = "wan";
+ $gatewayip = get_interface_gateway("wan");
+ @file_put_contents("{$g['tmp_path']}/{$defaultif}_defaultgw", $gatewayip);
+ }
+ if ($foundgwv6 == false) {
+ $defaultifv6 = get_real_interface("wan");
+ $interfacegwv6 = "wan";
+ $gatewayipv6 = get_interface_gateway_v6("wan");
+ @file_put_contents("{$g['tmp_path']}/{$defaultifv6}_defaultgwv6", $gatewayipv6);
+ }
+ $dont_add_route = false;
+ /* if OLSRD is enabled, allow WAN to house DHCP. */
+ if (is_array($config['installedpackages']['olsrd'])) {
+ foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
+ if (($olsrd['enabledyngw'] == "on") && ($olsrd['enable'] == "on")) {
+ $dont_add_route = true;
+ log_error(sprintf(gettext("Not adding default route because OLSR dynamic gateway is enabled.")));
+ break;
+ }
+ }
+ }
+
+ if ($dont_add_route == false) {
+ if (!empty($interface) && $interface != $interfacegw) {
+ ;
+ } else if (is_ipaddrv4($gatewayip)) {
+ log_error("ROUTING: setting default route to $gatewayip");
+ mwexec("/sbin/route change -inet default " . escapeshellarg($gatewayip));
+ }
+
+ if (!empty($interface) && $interface != $interfacegwv6) {
+ ;
+ } else if (is_ipaddrv6($gatewayipv6)) {
+ $ifscope = "";
+ if (is_linklocal($gatewayipv6) && !strpos($gatewayipv6, '%')) {
+ $ifscope = "%{$defaultifv6}";
+ }
+ log_error("ROUTING: setting IPv6 default route to {$gatewayipv6}{$ifscope}");
+ mwexec("/sbin/route change -inet6 default " . escapeshellarg("{$gatewayipv6}{$ifscope}"));
+ }
+ }
+
+ system_staticroutes_configure($interface, false);
+
+ return 0;
+}
+
+function system_staticroutes_configure($interface = "", $update_dns = false) {
+ global $config, $g, $aliastable;
+
+ $filterdns_list = array();
+
+ $static_routes = get_staticroutes(false, true);
+ if (count($static_routes)) {
+ $gateways_arr = return_gateways_array(false, true);
+
+ foreach ($static_routes as $rtent) {
+ if (empty($gateways_arr[$rtent['gateway']])) {
+ log_error(sprintf(gettext("Static Routes: Gateway IP could not be found for %s"), $rtent['network']));
+ continue;
+ }
+ $gateway = $gateways_arr[$rtent['gateway']];
+ if (!empty($interface) && $interface != $gateway['friendlyiface']) {
+ continue;
+ }
+
+ $gatewayip = $gateway['gateway'];
+ $interfacegw = $gateway['interface'];
+
+ $blackhole = "";
+ if (!strcasecmp("Null", substr($rtent['gateway'], 0, 3))) {
+ $blackhole = "-blackhole";
+ }
+
+ if (!is_fqdn($rtent['network']) && !is_subnet($rtent['network'])) {
+ continue;
+ }
+
+ $dnscache = array();
+ if ($update_dns === true) {
+ if (is_subnet($rtent['network'])) {
+ continue;
+ }
+ $dnscache = explode("\n", trim(compare_hostname_to_dnscache($rtent['network'])));
+ if (empty($dnscache)) {
+ continue;
+ }
+ }
+
+ if (is_subnet($rtent['network'])) {
+ $ips = array($rtent['network']);
+ } else {
+ if (!isset($rtent['disabled'])) {
+ $filterdns_list[] = $rtent['network'];
+ }
+ $ips = add_hostname_to_watch($rtent['network']);
+ }
+
+ foreach ($dnscache as $ip) {
+ if (in_array($ip, $ips)) {
+ continue;
+ }
+ mwexec("/sbin/route delete " . escapeshellarg($ip), true);
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - route delete $ip ");
+ }
+ }
+
+ if (isset($rtent['disabled'])) {
+ /* XXX: This can break things by deleting routes that shouldn't be deleted - OpenVPN, dynamic routing scenarios, etc. redmine #3709 */
+ foreach ($ips as $ip) {
+ mwexec("/sbin/route delete " . escapeshellarg($ip), true);
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - route delete $ip ");
+ }
+ }
+ continue;
+ }
+
+ foreach ($ips as $ip) {
+ if (is_ipaddrv4($ip)) {
+ $ip .= "/32";
+ }
+ // do NOT do the same check here on v6, is_ipaddrv6 returns true when including the CIDR mask. doing so breaks v6 routes
+
+ $inet = (is_subnetv6($ip) ? "-inet6" : "-inet");
+
+ $cmd = "/sbin/route change {$inet} {$blackhole} " . escapeshellarg($ip) . " ";
+
+ if (is_subnet($ip)) {
+ if (is_ipaddr($gatewayip)) {
+ mwexec($cmd . escapeshellarg($gatewayip));
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - $cmd $gatewayip");
+ }
+ } else if (!empty($interfacegw)) {
+ mwexec($cmd . "-iface " . escapeshellarg($interfacegw));
+ if (isset($config['system']['route-debug'])) {
+ $mt = microtime();
+ log_error("ROUTING debug: $mt - $cmd -iface $interfacegw ");
+ }
+ }
+ }
+ }
+ }
+ unset($gateways_arr);
+ }
+ unset($static_routes);
+
+ if ($update_dns === false) {
+ if (count($filterdns_list)) {
+ $interval = 60;
+ $hostnames = "";
+ array_unique($filterdns_list);
+ foreach ($filterdns_list as $hostname) {
+ $hostnames .= "cmd {$hostname} '/usr/local/sbin/pfSctl -c \"service reload routedns\"'\n";
+ }
+ file_put_contents("{$g['varetc_path']}/filterdns-route.hosts", $hostnames);
+ unset($hostnames);
+
+ if (isvalidpid("{$g['varrun_path']}/filterdns-route.pid")) {
+ sigkillbypid("{$g['varrun_path']}/filterdns-route.pid", "HUP");
+ } else {
+ mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-route.pid -i {$interval} -c {$g['varetc_path']}/filterdns-route.hosts -d 1");
+ }
+ } else {
+ killbypid("{$g['varrun_path']}/filterdns-route.pid");
+ @unlink("{$g['varrun_path']}/filterdns-route.pid");
+ }
+ }
+ unset($filterdns_list);
+
+ return 0;
+}
+
+function system_routing_enable() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_routing_enable() being called $mt\n";
+ }
+
+ set_sysctl(array(
+ "net.inet.ip.forwarding" => "1",
+ "net.inet6.ip6.forwarding" => "1"
+ ));
+
+ return;
+}
+
+function system_syslogd_fixup_server($server) {
+ /* If it's an IPv6 IP alone, encase it in brackets */
+ if (is_ipaddrv6($server)) {
+ return "[$server]";
+ } else {
+ return $server;
+ }
+}
+
+function system_syslogd_get_remote_servers($syslogcfg, $facility = "*.*") {
+ // Rather than repeatedly use the same code, use this function to build a list of remote servers.
+ $facility .= " ".
+ $remote_servers = "";
+ $pad_to = 56;
+ $padding = ceil(($pad_to - strlen($facility))/8)+1;
+ if ($syslogcfg['remoteserver']) {
+ $remote_servers .= "{$facility}" . str_repeat("\t", $padding) . "@" . system_syslogd_fixup_server($syslogcfg['remoteserver']) . "\n";
+ }
+ if ($syslogcfg['remoteserver2']) {
+ $remote_servers .= "{$facility}" . str_repeat("\t", $padding) . "@" . system_syslogd_fixup_server($syslogcfg['remoteserver2']) . "\n";
+ }
+ if ($syslogcfg['remoteserver3']) {
+ $remote_servers .= "{$facility}" . str_repeat("\t", $padding) . "@" . system_syslogd_fixup_server($syslogcfg['remoteserver3']) . "\n";
+ }
+ return $remote_servers;
+}
+
+function system_syslogd_start() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_syslogd_start() being called $mt\n";
+ }
+
+ mwexec("/etc/rc.d/hostid start");
+
+ $syslogcfg = $config['syslog'];
+
+ if (platform_booting()) {
+ echo gettext("Starting syslog...");
+ }
+
+ if (is_process_running("fifolog_writer")) {
+ mwexec('/bin/pkill fifolog_writer');
+ }
+
+ // Which logging type are we using this week??
+ if (isset($config['system']['disablesyslogclog'])) {
+ $log_directive = "";
+ $log_create_directive = "/usr/bin/touch ";
+ $log_size = "";
+ } else if (isset($config['system']['usefifolog'])) {
+ $log_directive = "|/usr/sbin/fifolog_writer ";
+ $log_size = isset($config['syslog']['logfilesize']) ? $config['syslog']['logfilesize'] : "10240";
+ $log_create_directive = "/usr/sbin/fifolog_create -s ";
+ } else { // Defaults to CLOG
+ $log_directive = "%";
+ $log_size = isset($config['syslog']['logfilesize']) ? $config['syslog']['logfilesize'] : "10240";
+ $log_create_directive = "/usr/local/sbin/clog -i -s ";
+ }
+
+ $syslogd_extra = "";
+ if (isset($syslogcfg)) {
+ $separatelogfacilities = array('ntp', 'ntpd', 'ntpdate', 'charon', 'ipsec_starter', 'openvpn', 'pptps', 'poes', 'l2tps', 'relayd', 'hostapd', 'dnsmasq', 'filterdns', 'unbound', 'dhcpd', 'dhcrelay', 'dhclient', 'dhcp6c', 'apinger', 'radvd', 'routed', 'olsrd', 'zebra', 'ospfd', 'bgpd', 'miniupnpd', 'filterlog');
+ $syslogconf = "";
+ if ($config['installedpackages']['package']) {
+ foreach ($config['installedpackages']['package'] as $package) {
+ if ($package['logging']) {
+ array_push($separatelogfacilities, $package['logging']['facilityname']);
+ if (!is_file($g['varlog_path'].'/'.$package['logging']['logfilename'])) {
+ mwexec("{$log_create_directive} {$log_size} {$g['varlog_path']}/{$package['logging']['logfilename']}");
+ }
+ $syslogconf .= "!{$package['logging']['facilityname']}\n*.*\t\t\t\t\t\t {$log_directive}{$g['varlog_path']}/{$package['logging']['logfilename']}\n";
+ }
+ }
+ }
+ $facilitylist = implode(',', array_unique($separatelogfacilities));
+ $syslogconf .= "!radvd,routed,olsrd,zebra,ospfd,bgpd,miniupnpd\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/routing.log\n";
+ }
+
+ $syslogconf .= "!ntp,ntpd,ntpdate\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/ntpd.log\n";
+ }
+
+ $syslogconf .= "!ppp\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/ppp.log\n";
+ }
+
+ $syslogconf .= "!pptps\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/pptps.log\n";
+ }
+
+ $syslogconf .= "!poes\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/poes.log\n";
+ }
+
+ $syslogconf .= "!l2tps\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/l2tps.log\n";
+ }
+
+ $syslogconf .= "!charon,ipsec_starter\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/ipsec.log\n";
+ }
+ if (isset($syslogcfg['vpn'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!openvpn\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/openvpn.log\n";
+ }
+ if (isset($syslogcfg['vpn'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!apinger\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/gateways.log\n";
+ }
+ if (isset($syslogcfg['apinger'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!dnsmasq,filterdns,unbound\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/resolver.log\n";
+ }
+
+ $syslogconf .= "!dhcpd,dhcrelay,dhclient,dhcp6c\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/dhcpd.log\n";
+ }
+ if (isset($syslogcfg['dhcp'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!relayd\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/relayd.log\n";
+ }
+ if (isset($syslogcfg['relayd'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!hostapd\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/wireless.log\n";
+ }
+ if (isset($syslogcfg['hostapd'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!filterlog\n";
+ $syslogconf .= "*.* {$log_directive}{$g['varlog_path']}/filter.log\n";
+ if (isset($syslogcfg['filter'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ $syslogconf .= "!-{$facilitylist}\n";
+ if (!isset($syslogcfg['disablelocallogging'])) {
+ $syslogconf .= <<<EOD
+local3.* {$log_directive}{$g['varlog_path']}/vpn.log
+local4.* {$log_directive}{$g['varlog_path']}/portalauth.log
+local7.* {$log_directive}{$g['varlog_path']}/dhcpd.log
+*.notice;kern.debug;lpr.info;mail.crit;daemon.none; {$log_directive}{$g['varlog_path']}/system.log
+news.err;local0.none;local3.none;local4.none; {$log_directive}{$g['varlog_path']}/system.log
+local7.none {$log_directive}{$g['varlog_path']}/system.log
+security.* {$log_directive}{$g['varlog_path']}/system.log
+auth.info;authpriv.info;daemon.info {$log_directive}{$g['varlog_path']}/system.log
+auth.info;authpriv.info |exec /usr/local/sbin/sshlockout_pf 15
+*.emerg *
+
+EOD;
+ }
+ if (isset($syslogcfg['vpn'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "local3.*");
+ }
+ if (isset($syslogcfg['portalauth'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "local4.*");
+ }
+ if (isset($syslogcfg['dhcp'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "local7.*");
+ }
+ if (isset($syslogcfg['system'])) {
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.notice;kern.debug;lpr.info;mail.crit;");
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "news.err;local0.none;local3.none;local7.none");
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "security.*");
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "auth.info;authpriv.info;daemon.info");
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.emerg");
+ }
+ if (isset($syslogcfg['logall'])) {
+ // Make everything mean everything, including facilities excluded above.
+ $syslogconf .= "!*\n";
+ $syslogconf .= system_syslogd_get_remote_servers($syslogcfg, "*.*");
+ }
+
+ if (isset($syslogcfg['zmqserver'])) {
+ $syslogconf .= <<<EOD
+*.* ^{$syslogcfg['zmqserver']}
+
+EOD;
+ }
+ /* write syslog.conf */
+ if (!@file_put_contents("{$g['varetc_path']}/syslog.conf", $syslogconf)) {
+ printf(gettext("Error: cannot open syslog.conf in system_syslogd_start().%s"), "\n");
+ unset($syslogconf);
+ return 1;
+ }
+ unset($syslogconf);
+
+ // Ensure that the log directory exists
+ if (!is_dir("{$g['dhcpd_chroot_path']}/var/run")) {
+ exec("/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run");
+ }
+
+ $sourceip = "";
+ if (!empty($syslogcfg['sourceip'])) {
+ if ($syslogcfg['ipproto'] == "ipv6") {
+ $ifaddr = is_ipaddr($syslogcfg['sourceip']) ? $syslogcfg['sourceip'] : get_interface_ipv6($syslogcfg['sourceip']);
+ if (!is_ipaddr($ifaddr)) {
+ $ifaddr = get_interface_ip($syslogcfg['sourceip']);
+ }
+ } else {
+ $ifaddr = is_ipaddr($syslogcfg['sourceip']) ? $syslogcfg['sourceip'] : get_interface_ip($syslogcfg['sourceip']);
+ if (!is_ipaddr($ifaddr)) {
+ $ifaddr = get_interface_ipv6($syslogcfg['sourceip']);
+ }
+ }
+ if (is_ipaddr($ifaddr)) {
+ $sourceip = "-b {$ifaddr}";
+ }
+ }
+
+ $syslogd_extra = "-f {$g['varetc_path']}/syslog.conf {$sourceip}";
+ }
+
+ if (isvalidpid("{$g['varrun_path']}/syslog.pid")) {
+ sigkillbypid("{$g['varrun_path']}/syslog.pid", "TERM");
+ usleep(100000); // syslogd often doesn't respond to a TERM quickly enough for the starting of syslogd below to be successful
+ }
+
+ if (isvalidpid("{$g['varrun_path']}/syslog.pid")) {
+ // if it still hasn't responded to the TERM, KILL it.
+ sigkillbypid("{$g['varrun_path']}/syslog.pid", "KILL");
+ usleep(100000);
+ }
+
+
+ $retval = mwexec_bg("/usr/sbin/syslogd -s -c -c -l {$g['dhcpd_chroot_path']}/var/run/log -P {$g['varrun_path']}/syslog.pid {$syslogd_extra}");
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+
+ return $retval;
+}
+
+function system_webgui_create_certificate() {
+ global $config, $g;
+
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ $a_ca =& $config['ca'];
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+ $a_cert =& $config['cert'];
+ log_error("Creating SSL Certificate for this host");
+
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = gettext("webConfigurator default ({$cert['refid']})");
+
+ $dn = array(
+ 'countryName' => "US",
+ 'stateOrProvinceName' => "State",
+ 'localityName' => "Locality",
+ 'organizationName' => "{$g['product_name']} webConfigurator Self-Signed Certificate",
+ 'emailAddress' => "admin@{$config['system']['hostname']}.{$config['system']['domain']}",
+ 'commonName' => "{$config['system']['hostname']}-{$cert['refid']}");
+ $old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
+ if (!cert_create($cert, null, 2048, 2000, $dn, "self-signed", "sha256")) {
+ while ($ssl_err = openssl_error_string()) {
+ log_error("Error creating WebGUI Certificate: openssl library returns: " . $ssl_err);
+ }
+ error_reporting($old_err_level);
+ return null;
+ }
+ error_reporting($old_err_level);
+
+ $a_cert[] = $cert;
+ $config['system']['webgui']['ssl-certref'] = $cert['refid'];
+ write_config(gettext("Generated new self-signed HTTPS certificate ({$cert['refid']})"));
+ return $cert;
+}
+
+function system_webgui_start() {
+ global $config, $g;
+
+ if (platform_booting()) {
+ echo gettext("Starting webConfigurator...");
+ }
+
+ chdir($g['www_path']);
+
+ /* defaults */
+ $portarg = "80";
+ $crt = "";
+ $key = "";
+ $ca = "";
+
+ /* non-standard port? */
+ if (isset($config['system']['webgui']['port']) && $config['system']['webgui']['port'] <> "") {
+ $portarg = "{$config['system']['webgui']['port']}";
+ }
+
+ if ($config['system']['webgui']['protocol'] == "https") {
+ // Ensure that we have a webConfigurator CERT
+ $cert =& lookup_cert($config['system']['webgui']['ssl-certref']);
+ if (!is_array($cert) || !$cert['crt'] || !$cert['prv']) {
+ $cert = system_webgui_create_certificate();
+ }
+ $crt = base64_decode($cert['crt']);
+ $key = base64_decode($cert['prv']);
+
+ if (!$config['system']['webgui']['port']) {
+ $portarg = "443";
+ }
+ $ca = ca_chain($cert);
+ }
+
+ /* generate lighttpd configuration */
+ system_generate_lighty_config("{$g['varetc_path']}/lighty-webConfigurator.conf",
+ $crt, $key, $ca, "lighty-webConfigurator.pid", $portarg, "/usr/local/www/",
+ "cert.pem", "ca.pem");
+
+ /* kill any running lighttpd */
+ killbypid("{$g['varrun_path']}/lighty-webConfigurator.pid");
+
+ sleep(1);
+
+ @unlink("{$g['varrun_path']}/lighty-webConfigurator.pid");
+
+ /* attempt to start lighthttpd */
+ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-webConfigurator.conf");
+
+ if (platform_booting()) {
+ if ($res == 0) {
+ echo gettext("done.") . "\n";
+ } else {
+ echo gettext("failed!") . "\n";
+ }
+ }
+
+ return $res;
+}
+
+function system_generate_lighty_config($filename,
+ $cert,
+ $key,
+ $ca,
+ $pid_file,
+ $port = 80,
+ $document_root = "/usr/local/www/",
+ $cert_location = "cert.pem",
+ $ca_location = "ca.pem",
+ $captive_portal = false) {
+
+ global $config, $g;
+
+ if (!is_dir("{$g['tmp_path']}/lighttpdcompress")) {
+ mkdir("{$g['tmp_path']}/lighttpdcompress");
+ }
+
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_generate_lighty_config() being called $mt\n";
+ }
+
+ if ($captive_portal !== false) {
+ $captiveportal = ",\"mod_rewrite\",\"mod_evasive\"";
+ $captive_portal_rewrite = "url.rewrite-once = ( \"(.*captiveportal.*)\" => \"$1\", \"(.*)\" => \"/index.php?zone={$captive_portal}&redirurl=$1\" )\n";
+
+ $maxprocperip = $config['captiveportal'][$captive_portal]['maxprocperip'];
+ if (empty($maxprocperip)) {
+ $maxprocperip = 10;
+ }
+ $captive_portal_mod_evasive = "evasive.max-conns-per-ip = {$maxprocperip}";
+
+ $server_upload_dirs = "server.upload-dirs = ( \"{$g['tmp_path']}/captiveportal/\" )\n";
+ if (!is_dir("{$g['tmp_path']}/captiveportal")) {
+ @mkdir("{$g['tmp_path']}/captiveportal", 0555);
+ }
+ $server_max_request_size = "server.max-request-size = 384";
+ $cgi_config = "";
+ } else {
+ $captiveportal = ",\"mod_cgi\"";
+ $captive_portal_rewrite = "";
+ $captive_portal_mod_evasive = "";
+ $server_upload_dirs = "server.upload-dirs = ( \"{$g['upload_path']}/\", \"{$g['tmp_path']}/\", \"/var/\" )\n";
+ $server_max_request_size = "server.max-request-size = 2097152";
+ $cgi_config = "cgi.assign = ( \".cgi\" => \"\" )";
+ }
+
+ if (empty($port)) {
+ $lighty_port = "80";
+ } else {
+ $lighty_port = $port;
+ }
+
+ $memory = get_memory();
+ $realmem = $memory[1];
+
+ // Determine web GUI process settings and take into account low memory systems
+ if ($realmem < 255) {
+ $max_procs = 1;
+ } else {
+ $max_procs = ($config['system']['webgui']['max_procs']) ? $config['system']['webgui']['max_procs'] : 2;
+ }
+
+ // Ramp up captive portal max procs, assuming each PHP process can consume up to 64MB RAM
+ if ($captive_portal !== false) {
+ if ($realmem > 135 and $realmem < 256) {
+ $max_procs += 1; // 2 worker processes
+ } else if ($realmem > 255 and $realmem < 513) {
+ $max_procs += 2; // 3 worker processes
+ } else if ($realmem > 512) {
+ $max_procs += 4; // 6 worker processes
+ }
+ if ($max_procs > 1) {
+ $max_php_children = intval($max_procs/2);
+ } else {
+ $max_php_children = 1;
+ }
+
+ } else {
+ if ($realmem < 78) {
+ $max_php_children = 0;
+ } else {
+ $max_php_children = 1;
+ }
+ }
+
+ if (!isset($config['syslog']['nologlighttpd'])) {
+ $lighty_use_syslog = <<<EOD
+## where to send error-messages to
+server.errorlog-use-syslog="enable"
+EOD;
+ }
+
+
+ if ($captive_portal !== false) {
+ $fast_cgi_path = "{$g['tmp_path']}/php-fastcgi-{$captive_portal}.socket";
+ $fastcgi_config = <<<EOD
+#### fastcgi module
+## read fastcgi.txt for more info
+fastcgi.server = ( ".php" =>
+ ( "localhost" =>
+ (
+ "socket" => "{$fast_cgi_path}",
+ "max-procs" => {$max_procs},
+ "bin-environment" => (
+ "PHP_FCGI_CHILDREN" => "{$max_php_children}",
+ "PHP_FCGI_MAX_REQUESTS" => "500"
+ ),
+ "bin-path" => "/usr/local/bin/php-cgi"
+ )
+ )
+)
+
+EOD;
+ } else {
+ $fast_cgi_path = "{$g['varrun_path']}/php-fpm.socket";
+ $fastcgi_config = <<<EOD
+#### fastcgi module
+## read fastcgi.txt for more info
+fastcgi.server = ( ".php" =>
+ ( "localhost" =>
+ (
+ "socket" => "{$fast_cgi_path}",
+ "broken-scriptfilename" => "enable"
+ )
+ )
+)
+
+EOD;
+ }
+
+
+ $lighty_config = <<<EOD
+#
+# lighttpd configuration file
+#
+# use a it as base for lighttpd 1.0.0 and above
+#
+############ Options you really have to take care of ####################
+
+## FreeBSD!
+server.event-handler = "freebsd-kqueue"
+server.network-backend = "writev"
+#server.use-ipv6 = "enable"
+
+## modules to load
+server.modules = ( "mod_access", "mod_expire", "mod_compress", "mod_redirect",
+ {$captiveportal}, "mod_fastcgi"
+)
+
+server.max-keep-alive-requests = 15
+server.max-keep-alive-idle = 30
+
+## a static document-root, for virtual-hosting take look at the
+## server.virtual-* options
+server.document-root = "{$document_root}"
+{$captive_portal_rewrite}
+
+# Maximum idle time with nothing being written (php downloading)
+server.max-write-idle = 999
+
+{$lighty_use_syslog}
+
+# files to check for if .../ is requested
+server.indexfiles = ( "index.php", "index.html",
+ "index.htm", "default.htm" )
+
+# mimetype mapping
+mimetype.assign = (
+ ".pdf" => "application/pdf",
+ ".sig" => "application/pgp-signature",
+ ".spl" => "application/futuresplash",
+ ".class" => "application/octet-stream",
+ ".ps" => "application/postscript",
+ ".torrent" => "application/x-bittorrent",
+ ".dvi" => "application/x-dvi",
+ ".gz" => "application/x-gzip",
+ ".pac" => "application/x-ns-proxy-autoconfig",
+ ".swf" => "application/x-shockwave-flash",
+ ".tar.gz" => "application/x-tgz",
+ ".tgz" => "application/x-tgz",
+ ".tar" => "application/x-tar",
+ ".zip" => "application/zip",
+ ".mp3" => "audio/mpeg",
+ ".m3u" => "audio/x-mpegurl",
+ ".wma" => "audio/x-ms-wma",
+ ".wax" => "audio/x-ms-wax",
+ ".ogg" => "audio/x-wav",
+ ".wav" => "audio/x-wav",
+ ".gif" => "image/gif",
+ ".jpg" => "image/jpeg",
+ ".jpeg" => "image/jpeg",
+ ".png" => "image/png",
+ ".xbm" => "image/x-xbitmap",
+ ".xpm" => "image/x-xpixmap",
+ ".xwd" => "image/x-xwindowdump",
+ ".css" => "text/css",
+ ".html" => "text/html",
+ ".htm" => "text/html",
+ ".js" => "text/javascript",
+ ".asc" => "text/plain",
+ ".c" => "text/plain",
+ ".conf" => "text/plain",
+ ".text" => "text/plain",
+ ".txt" => "text/plain",
+ ".dtd" => "text/xml",
+ ".xml" => "text/xml",
+ ".mpeg" => "video/mpeg",
+ ".mpg" => "video/mpeg",
+ ".mov" => "video/quicktime",
+ ".qt" => "video/quicktime",
+ ".avi" => "video/x-msvideo",
+ ".asf" => "video/x-ms-asf",
+ ".asx" => "video/x-ms-asf",
+ ".wmv" => "video/x-ms-wmv",
+ ".bz2" => "application/x-bzip",
+ ".tbz" => "application/x-bzip-compressed-tar",
+ ".tar.bz2" => "application/x-bzip-compressed-tar"
+ )
+
+# Use the "Content-Type" extended attribute to obtain mime type if possible
+#mimetypes.use-xattr = "enable"
+
+## deny access the file-extensions
+#
+# ~ is for backupfiles from vi, emacs, joe, ...
+# .inc is often used for code includes which should in general not be part
+# of the document-root
+url.access-deny = ( "~", ".inc" )
+
+
+######### Options that are good to be but not necessary to be changed #######
+
+## disable server header
+server.tag = ""
+
+## bind to port (default: 80)
+
+EOD;
+
+ $lighty_config .= "server.bind = \"0.0.0.0\"\n";
+ $lighty_config .= "server.port = {$lighty_port}\n";
+ $lighty_config .= "\$SERVER[\"socket\"] == \"0.0.0.0:{$lighty_port}\" { }\n";
+ $lighty_config .= "\$SERVER[\"socket\"] == \"[::]:{$lighty_port}\" { \n";
+ if ($cert <> "" and $key <> "") {
+ $lighty_config .= "\n";
+ $lighty_config .= "## ssl configuration\n";
+ $lighty_config .= "ssl.engine = \"enable\"\n";
+ $lighty_config .= "ssl.pemfile = \"{$g['varetc_path']}/{$cert_location}\"\n\n";
+ if ($ca <> "") {
+ $lighty_config .= "ssl.ca-file = \"{$g['varetc_path']}/{$ca_location}\"\n\n";
+ }
+ }
+ $lighty_config .= " }\n";
+
+
+ $lighty_config .= <<<EOD
+
+## error-handler for status 404
+#server.error-handler-404 = "/error-handler.html"
+#server.error-handler-404 = "/error-handler.php"
+
+## to help the rc.scripts
+server.pid-file = "{$g['varrun_path']}/{$pid_file}"
+
+## virtual directory listings
+server.dir-listing = "disable"
+
+## enable debugging
+debug.log-request-header = "disable"
+debug.log-response-header = "disable"
+debug.log-request-handling = "disable"
+debug.log-file-not-found = "disable"
+
+# gzip compression
+compress.cache-dir = "{$g['tmp_path']}/lighttpdcompress/"
+compress.filetype = ("text/plain","text/css", "text/xml", "text/javascript" )
+
+{$server_upload_dirs}
+
+{$server_max_request_size}
+
+{$fastcgi_config}
+
+{$cgi_config}
+
+{$captive_portal_mod_evasive}
+
+expire.url = (
+ "" => "access 50 hours",
+ )
+
+EOD;
+
+ $cert = str_replace("\r", "", $cert);
+ $key = str_replace("\r", "", $key);
+ $ca = str_replace("\r", "", $ca);
+
+ $cert = str_replace("\n\n", "\n", $cert);
+ $key = str_replace("\n\n", "\n", $key);
+ $ca = str_replace("\n\n", "\n", $ca);
+
+ if ($cert <> "" and $key <> "") {
+ $fd = fopen("{$g['varetc_path']}/{$cert_location}", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open cert.pem in system_webgui_start().%s"), "\n");
+ return 1;
+ }
+ chmod("{$g['varetc_path']}/{$cert_location}", 0600);
+ fwrite($fd, $cert);
+ fwrite($fd, "\n");
+ fwrite($fd, $key);
+ fclose($fd);
+ if (!(empty($ca) || (strlen(trim($ca)) == 0))) {
+ $fd = fopen("{$g['varetc_path']}/{$ca_location}", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open ca.pem in system_webgui_start().%s"), "\n");
+ return 1;
+ }
+ chmod("{$g['varetc_path']}/{$ca_location}", 0600);
+ fwrite($fd, $ca);
+ fclose($fd);
+ }
+ $lighty_config .= "\n";
+ $lighty_config .= "## " . gettext("ssl configuration") . "\n";
+ $lighty_config .= "ssl.engine = \"enable\"\n";
+ $lighty_config .= "ssl.pemfile = \"{$g['varetc_path']}/{$cert_location}\"\n\n";
+
+ // SSLv2/3 is deprecated, force use of TLS
+ $lighty_config .= "ssl.use-sslv2 = \"disable\"\n";
+ $lighty_config .= "ssl.use-sslv3 = \"disable\"\n";
+
+ // where ssl.cipher-list is set, this is automatically enabled, but set it explicitly anyway.
+ $lighty_config .= "ssl.honor-cipher-order = \"enable\"\n";
+
+ $lighty_config .= "ssl.cipher-list = \"AES128+EECDH:AES256+EECDH:AES128+EDH:AES256+EDH:AES128-SHA:AES256-SHA:!aNULL:!eNULL:!DSS\"\n";
+
+ if (!(empty($ca) || (strlen(trim($ca)) == 0))) {
+ $lighty_config .= "ssl.ca-file = \"{$g['varetc_path']}/{$ca_location}\"\n\n";
+ }
+ }
+
+ // Add HTTP to HTTPS redirect
+ if ($captive_portal === false && $config['system']['webgui']['protocol'] == "https" && !isset($config['system']['webgui']['disablehttpredirect'])) {
+ if ($lighty_port != "443") {
+ $redirectport = ":{$lighty_port}";
+ }
+ $lighty_config .= <<<EOD
+\$SERVER["socket"] == ":80" {
+ \$HTTP["host"] =~ "(.*)" {
+ url.redirect = ( "^/(.*)" => "https://%1{$redirectport}/$1" )
+ }
+}
+\$SERVER["socket"] == "[::]:80" {
+ \$HTTP["host"] =~ "(.*)" {
+ url.redirect = ( "^/(.*)" => "https://%1{$redirectport}/$1" )
+ }
+}
+EOD;
+ }
+
+ $fd = fopen("{$filename}", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open %s in system_generate_lighty_config().%s"), $filename, "\n");
+ return 1;
+ }
+ fwrite($fd, $lighty_config);
+ fclose($fd);
+
+ return 0;
+
+}
+
+function system_timezone_configure() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_timezone_configure() being called $mt\n";
+ }
+
+ $syscfg = $config['system'];
+
+ if (platform_booting()) {
+ echo gettext("Setting timezone...");
+ }
+
+ /* extract appropriate timezone file */
+ $timezone = $syscfg['timezone'];
+ if ($timezone) {
+ exec('/usr/bin/tar -tvzf /usr/share/zoneinfo.tgz', $tzs);
+ foreach ($tzs as $tz) {
+ if (preg_match(",{$timezone}$,", $tz)) {
+ break;
+ }
+ if (preg_match(",{$timezone} link to *(.*)$,", $tz, $matches)) {
+ $timezone = $matches[1];
+ break;
+ }
+ }
+ } else {
+ $timezone = "Etc/UTC";
+ }
+
+ conf_mount_rw();
+
+ exec("LANG=C /usr/bin/tar xzfO /usr/share/zoneinfo.tgz " .
+ escapeshellarg($timezone) . " > /etc/localtime");
+
+ mwexec("sync");
+ conf_mount_ro();
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+}
+
+function system_ntp_setup_gps($serialport) {
+ global $config, $g;
+ $gps_device = '/dev/gps0';
+ $serialport = '/dev/'.$serialport;
+
+ if (!file_exists($serialport)) {
+ return false;
+ }
+
+ conf_mount_rw();
+ // Create symlink that ntpd requires
+ unlink_if_exists($gps_device);
+ @symlink($serialport, $gps_device);
+
+ $gpsbaud = '4800';
+ if (is_array($config['ntpd']) && is_array($config['ntpd']['gps']) && !empty($config['ntpd']['gps']['speed'])) {
+ switch ($config['ntpd']['gps']['speed']) {
+ case '16':
+ $gpsbaud = '9600';
+ break;
+ case '32':
+ $gpsbaud = '19200';
+ break;
+ case '48':
+ $gpsbaud = '38400';
+ break;
+ case '64':
+ $gpsbaud = '57600';
+ break;
+ case '80':
+ $gpsbaud = '115200';
+ break;
+ }
+ }
+
+ /* Configure the serial port for raw IO and set the speed */
+ mwexec("stty -f {$serialport}.init raw speed {$gpsbaud}");
+
+ /* Send the following to the GPS port to initialize the GPS */
+ if (is_array($config['ntpd']) && is_array($config['ntpd']['gps']) && !empty($config['ntpd']['gps']['type'])) {
+ $gps_init = base64_decode($config['ntpd']['gps']['initcmd']);
+ } else {
+ $gps_init = base64_decode('JFBVQlgsNDAsR1NWLDAsMCwwLDAqNTkNCiRQVUJYLDQwLEdMTCwwLDAsMCwwKjVDDQokUFVCWCw0MCxaREEsMCwwLDAsMCo0NA0KJFBVQlgsNDAsVlRHLDAsMCwwLDAqNUUNCiRQVUJYLDQwLEdTViwwLDAsMCwwKjU5DQokUFVCWCw0MCxHU0EsMCwwLDAsMCo0RQ0KJFBVQlgsNDAsR0dBLDAsMCwwLDANCiRQVUJYLDQwLFRYVCwwLDAsMCwwDQokUFVCWCw0MCxSTUMsMCwwLDAsMCo0Ng0KJFBVQlgsNDEsMSwwMDA3LDAwMDMsNDgwMCwwDQokUFVCWCw0MCxaREEsMSwxLDEsMQ==');
+ }
+
+ /* XXX: Why not file_put_contents to the device */
+ @file_put_contents('/tmp/gps.init', $gps_init);
+ mwexec("cat /tmp/gps.init > {$serialport}");
+
+ /* Add /etc/remote entry in case we need to read from the GPS with tip */
+ if (intval(`grep -c '^gps0' /etc/remote`) == 0) {
+ @file_put_contents("/etc/remote", "gps0:dv={$serialport}:br#{$gpsbaud}:pa=none:", FILE_APPEND);
+ }
+
+ conf_mount_ro();
+
+ return true;
+}
+
+function system_ntp_setup_pps($serialport) {
+ global $config, $g;
+
+ $pps_device = '/dev/pps0';
+ $serialport = '/dev/'.$serialport;
+
+ if (!file_exists($serialport)) {
+ return false;
+ }
+
+ conf_mount_rw();
+ // Create symlink that ntpd requires
+ unlink_if_exists($pps_device);
+ @symlink($serialport, $pps_device);
+
+ conf_mount_ro();
+
+ return true;
+}
+
+
+function system_ntp_configure($start_ntpd=true) {
+ global $config, $g;
+
+ $driftfile = "/var/db/ntpd.drift";
+ $statsdir = "/var/log/ntp";
+ $gps_device = '/dev/gps0';
+
+ safe_mkdir($statsdir);
+
+ if (!is_array($config['ntpd'])) {
+ $config['ntpd'] = array();
+ }
+
+ $ntpcfg = "# \n";
+ $ntpcfg .= "# pfSense ntp configuration file \n";
+ $ntpcfg .= "# \n\n";
+ $ntpcfg .= "tinker panic 0 \n";
+
+ /* Add Orphan mode */
+ $ntpcfg .= "# Orphan mode stratum\n";
+ $ntpcfg .= 'tos orphan ';
+ if (!empty($config['ntpd']['orphan'])) {
+ $ntpcfg .= $config['ntpd']['orphan'];
+ } else {
+ $ntpcfg .= '12';
+ }
+ $ntpcfg .= "\n";
+
+ /* Add PPS configuration */
+ if (is_array($config['ntpd']['pps']) && !empty($config['ntpd']['pps']['port']) &&
+ file_exists('/dev/'.$config['ntpd']['pps']['port']) &&
+ system_ntp_setup_pps($config['ntpd']['pps']['port'])) {
+ $ntpcfg .= "\n";
+ $ntpcfg .= "# PPS Setup\n";
+ $ntpcfg .= 'server 127.127.22.0';
+ $ntpcfg .= ' minpoll 4 maxpoll 4';
+ if (empty($config['ntpd']['pps']['prefer'])) { /*note: this one works backwards */
+ $ntpcfg .= ' prefer';
+ }
+ if (!empty($config['ntpd']['pps']['noselect'])) {
+ $ntpcfg .= ' noselect ';
+ }
+ $ntpcfg .= "\n";
+ $ntpcfg .= 'fudge 127.127.22.0';
+ if (!empty($config['ntpd']['pps']['fudge1'])) {
+ $ntpcfg .= ' time1 ';
+ $ntpcfg .= $config['ntpd']['pps']['fudge1'];
+ }
+ if (!empty($config['ntpd']['pps']['flag2'])) {
+ $ntpcfg .= ' flag2 1';
+ }
+ if (!empty($config['ntpd']['pps']['flag3'])) {
+ $ntpcfg .= ' flag3 1';
+ } else {
+ $ntpcfg .= ' flag3 0';
+ }
+ if (!empty($config['ntpd']['pps']['flag4'])) {
+ $ntpcfg .= ' flag4 1';
+ }
+ if (!empty($config['ntpd']['pps']['refid'])) {
+ $ntpcfg .= ' refid ';
+ $ntpcfg .= $config['ntpd']['pps']['refid'];
+ }
+ $ntpcfg .= "\n";
+ }
+ /* End PPS configuration */
+
+ /* Add GPS configuration */
+ if (is_array($config['ntpd']['gps']) && !empty($config['ntpd']['gps']['port']) &&
+ file_exists('/dev/'.$config['ntpd']['gps']['port']) &&
+ system_ntp_setup_gps($config['ntpd']['gps']['port'])) {
+ $ntpcfg .= "\n";
+ $ntpcfg .= "# GPS Setup\n";
+ $ntpcfg .= 'server 127.127.20.0 mode ';
+ if (!empty($config['ntpd']['gps']['nmea']) || !empty($config['ntpd']['gps']['speed']) || !empty($config['ntpd']['gps']['subsec'])) {
+ if (!empty($config['ntpd']['gps']['nmea'])) {
+ $ntpmode = (int) $config['ntpd']['gps']['nmea'];
+ }
+ if (!empty($config['ntpd']['gps']['speed'])) {
+ $ntpmode += (int) $config['ntpd']['gps']['speed'];
+ }
+ if (!empty($config['ntpd']['gps']['subsec'])) {
+ $ntpmode += 128;
+ }
+ $ntpcfg .= (string) $ntpmode;
+ } else {
+ $ntpcfg .= '0';
+ }
+ $ntpcfg .= ' minpoll 4 maxpoll 4';
+ if (empty($config['ntpd']['gps']['prefer'])) { /*note: this one works backwards */
+ $ntpcfg .= ' prefer';
+ }
+ if (!empty($config['ntpd']['gps']['noselect'])) {
+ $ntpcfg .= ' noselect ';
+ }
+ $ntpcfg .= "\n";
+ $ntpcfg .= 'fudge 127.127.20.0';
+ if (!empty($config['ntpd']['gps']['fudge1'])) {
+ $ntpcfg .= ' time1 ';
+ $ntpcfg .= $config['ntpd']['gps']['fudge1'];
+ }
+ if (!empty($config['ntpd']['gps']['fudge2'])) {
+ $ntpcfg .= ' time2 ';
+ $ntpcfg .= $config['ntpd']['gps']['fudge2'];
+ }
+ if (!empty($config['ntpd']['gps']['flag1'])) {
+ $ntpcfg .= ' flag1 1';
+ } else {
+ $ntpcfg .= ' flag1 0';
+ }
+ if (!empty($config['ntpd']['gps']['flag2'])) {
+ $ntpcfg .= ' flag2 1';
+ }
+ if (!empty($config['ntpd']['gps']['flag3'])) {
+ $ntpcfg .= ' flag3 1';
+ } else {
+ $ntpcfg .= ' flag3 0';
+ }
+ if (!empty($config['ntpd']['gps']['flag4'])) {
+ $ntpcfg .= ' flag4 1';
+ }
+ if (!empty($config['ntpd']['gps']['refid'])) {
+ $ntpcfg .= ' refid ';
+ $ntpcfg .= $config['ntpd']['gps']['refid'];
+ }
+ $ntpcfg .= "\n";
+ } elseif (is_array($config['ntpd']) && !empty($config['ntpd']['gpsport']) &&
+ file_exists('/dev/'.$config['ntpd']['gpsport']) &&
+ system_ntp_setup_gps($config['ntpd']['gpsport'])) {
+ /* This handles a 2.1 and earlier config */
+ $ntpcfg .= "# GPS Setup\n";
+ $ntpcfg .= "server 127.127.20.0 mode 0 minpoll 4 maxpoll 4 prefer\n";
+ $ntpcfg .= "fudge 127.127.20.0 time1 0.155 time2 0.000 flag1 1 flag2 0 flag3 1\n";
+ // Fall back to local clock if GPS is out of sync?
+ $ntpcfg .= "server 127.127.1.0\n";
+ $ntpcfg .= "fudge 127.127.1.0 stratum 12\n";
+ }
+ /* End GPS configuration */
+
+ $ntpcfg .= "\n\n# Upstream Servers\n";
+ /* foreach through ntp servers and write out to ntpd.conf */
+ foreach (explode(' ', $config['system']['timeservers']) as $ts) {
+ $ntpcfg .= "server {$ts} iburst maxpoll 9";
+ if (substr_count($config['ntpd']['prefer'], $ts)) {
+ $ntpcfg .= ' prefer';
+ }
+ if (substr_count($config['ntpd']['noselect'], $ts)) {
+ $ntpcfg .= ' noselect';
+ }
+ $ntpcfg .= "\n";
+ }
+ unset($ts);
+
+ $ntpcfg .= "\n\n";
+ $ntpcfg .= "disable monitor\n"; //prevent NTP reflection attack, see https://forum.pfsense.org/index.php/topic,67189.msg389132.html#msg389132
+ if (!empty($config['ntpd']['clockstats']) || !empty($config['ntpd']['loopstats']) || !empty($config['ntpd']['peerstats'])) {
+ $ntpcfg .= "enable stats\n";
+ $ntpcfg .= 'statistics';
+ if (!empty($config['ntpd']['clockstats'])) {
+ $ntpcfg .= ' clockstats';
+ }
+ if (!empty($config['ntpd']['loopstats'])) {
+ $ntpcfg .= ' loopstats';
+ }
+ if (!empty($config['ntpd']['peerstats'])) {
+ $ntpcfg .= ' peerstats';
+ }
+ $ntpcfg .= "\n";
+ }
+ $ntpcfg .= "statsdir {$statsdir}\n";
+ $ntpcfg .= 'logconfig =syncall +clockall';
+ if (!empty($config['ntpd']['logpeer'])) {
+ $ntpcfg .= ' +peerall';
+ }
+ if (!empty($config['ntpd']['logsys'])) {
+ $ntpcfg .= ' +sysall';
+ }
+ $ntpcfg .= "\n";
+ $ntpcfg .= "driftfile {$driftfile}\n";
+ /* Access restrictions */
+ $ntpcfg .= 'restrict default';
+ if (empty($config['ntpd']['kod'])) { /*note: this one works backwards */
+ $ntpcfg .= ' kod limited';
+ }
+ if (empty($config['ntpd']['nomodify'])) { /*note: this one works backwards */
+ $ntpcfg .= ' nomodify';
+ }
+ if (!empty($config['ntpd']['noquery'])) {
+ $ntpcfg .= ' noquery';
+ }
+ if (empty($config['ntpd']['nopeer'])) { /*note: this one works backwards */
+ $ntpcfg .= ' nopeer';
+ }
+ if (empty($config['ntpd']['notrap'])) { /*note: this one works backwards */
+ $ntpcfg .= ' notrap';
+ }
+ if (!empty($config['ntpd']['noserve'])) {
+ $ntpcfg .= ' noserve';
+ }
+ $ntpcfg .= "\nrestrict -6 default";
+ if (empty($config['ntpd']['kod'])) { /*note: this one works backwards */
+ $ntpcfg .= ' kod limited';
+ }
+ if (empty($config['ntpd']['nomodify'])) { /*note: this one works backwards */
+ $ntpcfg .= ' nomodify';
+ }
+ if (!empty($config['ntpd']['noquery'])) {
+ $ntpcfg .= ' noquery';
+ }
+ if (empty($config['ntpd']['nopeer'])) { /*note: this one works backwards */
+ $ntpcfg .= ' nopeer';
+ }
+ if (!empty($config['ntpd']['noserve'])) {
+ $ntpcfg .= ' noserve';
+ }
+ if (empty($config['ntpd']['notrap'])) { /*note: this one works backwards */
+ $ntpcfg .= ' notrap';
+ }
+ $ntpcfg .= "\n";
+
+ /* A leapseconds file is really only useful if this clock is stratum 1 */
+ $ntpcfg .= "\n";
+ if (!empty($config['ntpd']['leapsec'])) {
+ $leapsec .= base64_decode($config['ntpd']['leapsec']);
+ file_put_contents('/var/db/leap-seconds', $leapsec);
+ $ntpcfg .= "leapfile /var/db/leap-seconds\n";
+ }
+
+
+ if (empty($config['ntpd']['interface'])) {
+ if (is_array($config['installedpackages']['openntpd']) && !empty($config['installedpackages']['openntpd']['config'][0]['interface'])) {
+ $interfaces = explode(",", $config['installedpackages']['openntpd']['config'][0]['interface']);
+ } else {
+ $interfaces = array();
+ }
+ } else {
+ $interfaces = explode(",", $config['ntpd']['interface']);
+ }
+
+ if (is_array($interfaces) && count($interfaces)) {
+ $ntpcfg .= "interface ignore all\n";
+ foreach ($interfaces as $interface) {
+ if (strstr($interface, "_vip")) {
+ $interface = get_configured_carp_interface_list($interface);
+ }
+ if (!is_ipaddr($interface)) {
+ $interface = get_real_interface($interface);
+ }
+ if (!empty($interface)) {
+ $ntpcfg .= "interface listen {$interface}\n";
+ }
+ }
+ }
+
+ /* open configuration for writing or bail */
+ if (!@file_put_contents("{$g['varetc_path']}/ntpd.conf", $ntpcfg)) {
+ log_error("Could not open {$g['varetc_path']}/ntpd.conf for writing");
+ return;
+ }
+
+ /* At bootup we just want to write out the config. */
+ if (!$start_ntpd) {
+ return;
+ }
+
+ /* if ntpd is running, kill it */
+ while (isvalidpid("{$g['varrun_path']}/ntpd.pid")) {
+ killbypid("{$g['varrun_path']}/ntpd.pid");
+ }
+ @unlink("{$g['varrun_path']}/ntpd.pid");
+
+ /* if /var/empty does not exist, create it */
+ if (!is_dir("/var/empty")) {
+ mkdir("/var/empty", 0775, true);
+ }
+
+ /* start opentpd, set time now and use /var/etc/ntpd.conf */
+ mwexec("/usr/local/sbin/ntpd -g -c {$g['varetc_path']}/ntpd.conf -p {$g['varrun_path']}/ntpd.pid", false, true);
+
+ // Note that we are starting up
+ log_error("NTPD is starting up.");
+ return;
+}
+
+function sync_system_time() {
+ global $config, $g;
+
+ if (platform_booting()) {
+ echo gettext("Syncing system time before startup...");
+ }
+
+ /* foreach through servers and write out to ntpd.conf */
+ foreach (explode(' ', $config['system']['timeservers']) as $ts) {
+ mwexec("/usr/local/sbin/ntpdate -s $ts");
+ }
+
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+
+}
+
+function system_halt() {
+ global $g;
+
+ system_reboot_cleanup();
+
+ mwexec("/usr/bin/nohup /etc/rc.halt > /dev/null 2>&1 &");
+}
+
+function system_reboot() {
+ global $g;
+
+ system_reboot_cleanup();
+
+ mwexec("nohup /etc/rc.reboot > /dev/null 2>&1 &");
+}
+
+function system_reboot_sync() {
+ global $g;
+
+ system_reboot_cleanup();
+
+ mwexec("/etc/rc.reboot > /dev/null 2>&1");
+}
+
+function system_reboot_cleanup() {
+ global $config, $cpzone;
+
+ mwexec("/usr/local/bin/beep.sh stop");
+ require_once("captiveportal.inc");
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpzone=>$cp) {
+ captiveportal_radius_stop_all();
+ captiveportal_send_server_accounting(true);
+ }
+ }
+ require_once("voucher.inc");
+ voucher_save_db_to_config();
+ require_once("pkg-utils.inc");
+ stop_packages();
+}
+
+function system_do_shell_commands($early = 0) {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_do_shell_commands() being called $mt\n";
+ }
+
+ if ($early) {
+ $cmdn = "earlyshellcmd";
+ } else {
+ $cmdn = "shellcmd";
+ }
+
+ if (is_array($config['system'][$cmdn])) {
+
+ /* *cmd is an array, loop through */
+ foreach ($config['system'][$cmdn] as $cmd) {
+ exec($cmd);
+ }
+
+ } elseif ($config['system'][$cmdn] <> "") {
+
+ /* execute single item */
+ exec($config['system'][$cmdn]);
+
+ }
+}
+
+function system_console_configure() {
+ global $config, $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_console_configure() being called $mt\n";
+ }
+
+ if (isset($config['system']['disableconsolemenu'])) {
+ touch("{$g['varetc_path']}/disableconsole");
+ } else {
+ unlink_if_exists("{$g['varetc_path']}/disableconsole");
+ }
+}
+
+function system_dmesg_save() {
+ global $g;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_dmesg_save() being called $mt\n";
+ }
+
+ $dmesg = "";
+ $_gb = exec("/sbin/dmesg", $dmesg);
+
+ /* find last copyright line (output from previous boots may be present) */
+ $lastcpline = 0;
+
+ for ($i = 0; $i < count($dmesg); $i++) {
+ if (strstr($dmesg[$i], "Copyright (c) 1992-")) {
+ $lastcpline = $i;
+ }
+ }
+
+ $fd = fopen("{$g['varlog_path']}/dmesg.boot", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open dmesg.boot in system_dmesg_save().%s"), "\n");
+ return 1;
+ }
+
+ for ($i = $lastcpline; $i < count($dmesg); $i++) {
+ fwrite($fd, $dmesg[$i] . "\n");
+ }
+
+ fclose($fd);
+ unset($dmesg);
+
+ return 0;
+}
+
+function system_set_harddisk_standby() {
+ global $g, $config;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_set_harddisk_standby() being called $mt\n";
+ }
+
+ if (isset($config['system']['harddiskstandby'])) {
+ if (platform_booting()) {
+ echo gettext('Setting hard disk standby... ');
+ }
+
+ $standby = $config['system']['harddiskstandby'];
+ // Check for a numeric value
+ if (is_numeric($standby)) {
+ // Sync the disk(s)
+ pfSense_sync();
+ if (set_single_sysctl('hw.ata.standby', (int)$standby)) {
+ // Reinitialize ATA-drives
+ mwexec('/usr/local/sbin/atareinit');
+ if (platform_booting()) {
+ echo gettext("done.") . "\n";
+ }
+ } else if (platform_booting()) {
+ echo gettext("failed!") . "\n";
+ }
+ } else if (platform_booting()) {
+ echo gettext("failed!") . "\n";
+ }
+ }
+}
+
+function system_setup_sysctl() {
+ global $config;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_setup_sysctl() being called $mt\n";
+ }
+
+ activate_sysctls();
+
+ if (isset($config['system']['sharednet'])) {
+ system_disable_arp_wrong_if();
+ }
+}
+
+function system_disable_arp_wrong_if() {
+ global $config;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_disable_arp_wrong_if() being called $mt\n";
+ }
+ set_sysctl(array(
+ "net.link.ether.inet.log_arp_wrong_iface" => "0",
+ "net.link.ether.inet.log_arp_movements" => "0"
+ ));
+}
+
+function system_enable_arp_wrong_if() {
+ global $config;
+ if (isset($config['system']['developerspew'])) {
+ $mt = microtime();
+ echo "system_enable_arp_wrong_if() being called $mt\n";
+ }
+ set_sysctl(array(
+ "net.link.ether.inet.log_arp_wrong_iface" => "1",
+ "net.link.ether.inet.log_arp_movements" => "1"
+ ));
+}
+
+function enable_watchdog() {
+ global $config;
+ return;
+ $install_watchdog = false;
+ $supported_watchdogs = array("Geode");
+ $file = file_get_contents("/var/log/dmesg.boot");
+ foreach ($supported_watchdogs as $sd) {
+ if (stristr($file, "Geode")) {
+ $install_watchdog = true;
+ }
+ }
+ if ($install_watchdog == true) {
+ if (is_process_running("watchdogd")) {
+ mwexec("/usr/bin/killall watchdogd", true);
+ }
+ exec("/usr/sbin/watchdogd");
+ }
+}
+
+function system_check_reset_button() {
+ global $g;
+
+ $specplatform = system_identify_specific_platform();
+
+ switch ($specplatform['name']) {
+ case 'alix':
+ case 'wrap':
+ case 'FW7541':
+ case 'APU':
+ case 'RCC-VE':
+ case 'RCC-DFF':
+ break;
+ default:
+ return 0;
+ }
+
+ $retval = mwexec("/usr/local/sbin/" . $specplatform['name'] . "resetbtn");
+
+ if ($retval == 99) {
+ /* user has pressed reset button for 2 seconds -
+ reset to factory defaults */
+ echo <<<EOD
+
+***********************************************************************
+* Reset button pressed - resetting configuration to factory defaults. *
+* The system will reboot after this completes. *
+***********************************************************************
+
+
+EOD;
+
+ reset_factory_defaults();
+ system_reboot_sync();
+ exit(0);
+ }
+
+ return 0;
+}
+
+/* attempt to identify the specific platform (for embedded systems)
+ Returns an array with two elements:
+ name => platform string (e.g. 'wrap', 'alix' etc.)
+ descr => human-readable description (e.g. "PC Engines WRAP")
+*/
+function system_identify_specific_platform() {
+ global $g;
+
+ if ($g['platform'] == 'generic-pc') {
+ return array('name' => 'generic-pc', 'descr' => gettext("Generic PC"));
+ }
+
+ if ($g['platform'] == 'generic-pc-cdrom') {
+ return array('name' => 'generic-pc-cdrom', 'descr' => gettext("Generic PC (CD-ROM)"));
+ }
+
+ /* Try to guess from smbios strings */
+ unset($output);
+ $_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output);
+ switch ($output[0]) {
+ case 'FW7541':
+ return (array('name' => 'FW7541', 'descr' => 'Netgate FW7541'));
+ break;
+ case 'APU':
+ return (array('name' => 'APU', 'descr' => 'Netgate APU'));
+ break;
+ case 'RCC-VE':
+ return (array('name' => 'RCC-VE', 'descr' => 'Netgate RCC-VE'));
+ break;
+ case 'DFFv2':
+ return (array('name' => 'RCC-DFF', 'descr' => 'Netgate RCC-DFF'));
+ break;
+ case 'SYS-5018A-FTN4':
+ case 'A1SAi':
+ return (array('name' => 'C2758', 'descr' => 'Super Micro C2758'));
+ break;
+ case 'SYS-5018D-FN4T':
+ return (array('name' => 'D1540-XG', 'descr' => 'Super Micro D1540-XG'));
+ break;
+ }
+
+ /* the rest of the code only deals with 'embedded' platforms */
+ if ($g['platform'] != 'nanobsd') {
+ return array('name' => $g['platform'], 'descr' => $g['platform']);
+ }
+
+ $dmesg = get_single_sysctl('hw.model');
+
+ if (strpos($dmesg, "PC Engines WRAP") !== false) {
+ return array('name' => 'wrap', 'descr' => gettext('PC Engines WRAP'));
+ }
+
+ if (strpos($dmesg, "PC Engines ALIX") !== false) {
+ return array('name' => 'alix', 'descr' => gettext('PC Engines ALIX'));
+ }
+
+ if (preg_match("/Soekris net45../", $dmesg, $matches)) {
+ return array('name' => 'net45xx', 'descr' => $matches[0]);
+ }
+
+ if (preg_match("/Soekris net48../", $dmesg, $matches)) {
+ return array('name' => 'net48xx', 'descr' => $matches[0]);
+ }
+
+ if (preg_match("/Soekris net55../", $dmesg, $matches)) {
+ return array('name' => 'net55xx', 'descr' => $matches[0]);
+ }
+
+ unset($dmesg);
+
+ $dmesg_boot = system_get_dmesg_boot();
+ if (strpos($dmesg_boot, "PC Engines ALIX") !== false) {
+ return array('name' => 'alix', 'descr' => gettext('PC Engines ALIX'));
+ }
+ unset($dmesg_boot);
+
+ /* unknown embedded platform */
+ return array('name' => 'embedded', 'descr' => gettext('embedded (unknown)'));
+}
+
+function system_get_dmesg_boot() {
+ global $g;
+
+ return file_get_contents("{$g['varlog_path']}/dmesg.boot");
+}
+
+?>
diff --git a/src/etc/inc/unbound.inc b/src/etc/inc/unbound.inc
new file mode 100644
index 0000000..043ced2
--- /dev/null
+++ b/src/etc/inc/unbound.inc
@@ -0,0 +1,717 @@
+<?php
+/*
+ unbound.inc
+ part of the pfSense project (https://www.pfsense.org)
+ Copyright (C) 2015 Warren Baker <warren@percol8.co.za>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/unbound /usr/local/sbin/unbound-anchor /usr/local/sbin/unbound-checkconf
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/unbound-control /usr/local/sbin/unbound-control-setup
+ pfSense_MODULE: unbound
+*/
+
+/* include all configuration functions */
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+function create_unbound_chroot_path() {
+ global $config, $g;
+
+ // Configure chroot
+ if (!is_dir($g['unbound_chroot_path'])) {
+ mkdir($g['unbound_chroot_path']);
+ chown($g['unbound_chroot_path'], "unbound");
+ chgrp($g['unbound_chroot_path'], "unbound");
+ }
+
+}
+
+/* Optimize Unbound for environment */
+function unbound_optimization() {
+ global $config;
+
+ $optimization_settings = array();
+
+ /*
+ * Set the number of threads equal to number of CPUs.
+ * Use 1 to disable threading, if for some reason this sysctl fails.
+ */
+ $numprocs = intval(get_single_sysctl('kern.smp.cpus'));
+ if ($numprocs > 1) {
+ $optimization['number_threads'] = "num-threads: {$numprocs}";
+ $optimize_num = pow(2, floor(log($numprocs, 2)));
+ } else {
+ $optimization['number_threads'] = "num-threads: 1";
+ $optimize_num = 4;
+ }
+
+ // Slabs to help reduce lock contention.
+ $optimization['msg_cache_slabs'] = "msg-cache-slabs: {$optimize_num}";
+ $optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$optimize_num}";
+ $optimization['infra_cache_slabs'] = "infra-cache-slabs: {$optimize_num}";
+ $optimization['key_cache_slabs'] = "key-cache-slabs: {$optimize_num}";
+
+ /*
+ * Larger socket buffer for busy servers
+ * Check that it is set to 4MB (by default the OS has it configured to 4MB)
+ */
+ if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
+ foreach ($config['sysctl']['item'] as $tunable) {
+ if ($tunable['tunable'] == 'kern.ipc.maxsockbuf') {
+ $so = floor(($tunable['value']/1024/1024)-4);
+ // Check to ensure that the number is not a negative
+ if ($so >= 4) {
+ // Limit to 32MB, users might set maxsockbuf very high for other reasons.
+ // We do not want unbound to fail because of that.
+ $so = min($so, 32);
+ $optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
+ } else {
+ unset($optimization['so_rcvbuf']);
+ }
+ }
+ }
+ }
+ // Safety check in case kern.ipc.maxsockbuf is not available.
+ if (!isset($optimization['so_rcvbuf'])) {
+ $optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
+ }
+
+ return $optimization;
+
+}
+
+function unbound_generate_config() {
+ global $config, $g;
+
+ // Setup optimization
+ $optimization = unbound_optimization();
+
+ // Setup DNSSEC support
+ if (isset($config['unbound']['dnssec'])) {
+ $module_config = "validator iterator";
+ $anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root.key";
+ } else {
+ $module_config = "iterator";
+ }
+
+ // Setup DNS Rebinding
+ if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
+ // Private-addresses for DNS Rebinding
+ $private_addr = <<<EOF
+# For DNS Rebinding prevention
+private-address: 10.0.0.0/8
+private-address: 172.16.0.0/12
+private-address: 169.254.0.0/16
+private-address: 192.168.0.0/16
+private-address: fd00::/8
+private-address: fe80::/10
+EOF;
+ }
+
+ // Determine interfaces to run on
+ $bindints = "";
+ if (!empty($config['unbound']['active_interface'])) {
+ $active_interfaces = explode(",", $config['unbound']['active_interface']);
+ if (in_array("all", $active_interfaces, true)) {
+ $bindints .= "interface: 0.0.0.0\n";
+ $bindints .= "interface: ::0\n";
+ $bindints .= "interface-automatic: yes\n";
+ } else {
+ foreach ($active_interfaces as $ubif) {
+ if (is_ipaddr($ubif)) {
+ //$bindints .= "interface: $ubif\n"; -- until redmine #4062 is fixed, then uncomment this.
+ } else {
+ $intip = get_interface_ip($ubif);
+ if (is_ipaddrv4($intip)) {
+ $bindints .= "interface: $intip\n";
+ }
+ $intip = get_interface_ipv6($ubif);
+ if (is_ipaddrv6($intip)) {
+ if (!is_linklocal($intip)) { // skipping link local for the moment to not break people's configs: https://redmine.pfsense.org/issues/4062
+ $bindints .= "interface: $intip\n";
+ }
+ }
+ }
+ }
+ }
+ } else {
+ $bindints .= "interface: 0.0.0.0\n";
+ $bindints .= "interface: ::0\n";
+ /* If the active interface array is empty, treat it the same as "All" as is done above. Otherwise it breaks CARP with a default config. */
+ $bindints .= "interface-automatic: yes\n";
+ }
+
+ // Determine interfaces to run on
+ $outgoingints = "";
+ if (!empty($config['unbound']['outgoing_interface'])) {
+ $outgoingints = "# Outgoing interfaces to be used\n";
+ $outgoing_interfaces = explode(",", $config['unbound']['outgoing_interface']);
+ foreach ($outgoing_interfaces as $outif) {
+ $outip = get_interface_ip($outif);
+ if (is_ipaddr($outip)) {
+ $outgoingints .= "outgoing-interface: $outip\n";
+ }
+ $outip = get_interface_ipv6($outif);
+ if (is_ipaddrv6($outip)) {
+ $outgoingints .= "outgoing-interface: $outip\n";
+ }
+ }
+ }
+
+ // Allow DNS Rebind for forwarded domains
+ if (isset($config['unbound']['domainoverrides']) && is_array($config['unbound']['domainoverrides'])) {
+ if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
+ $private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n";
+ $private_domains .= unbound_add_domain_overrides("private");
+ }
+ $reverse_zones .= unbound_add_domain_overrides("reverse");
+ }
+
+ // Configure static Host entries
+ unbound_add_host_entries();
+
+ // Configure Domain Overrides
+ unbound_add_domain_overrides();
+
+ // Configure Unbound statistics
+ $statistics = unbound_statistics();
+
+ // Configure Unbound access-lists
+ unbound_acls_config();
+
+ // Add custom Unbound options
+ if ($config['unbound']['custom_options']) {
+ $custom_options_source = explode("\n", base64_decode($config['unbound']['custom_options']));
+ $custom_options = "# Unbound custom options\n";
+ foreach ($custom_options_source as $ent) {
+ $custom_options .= $ent."\n";
+ }
+ }
+
+ // Server configuration variables
+ $port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
+ $hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
+ $hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
+ $harden_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
+ $prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
+ $prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
+ $outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
+ $incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
+ $edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
+ $num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
+ $jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
+ $cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
+ $cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
+ $infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
+ $infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
+ $unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
+ if ($unwanted_reply_threshold == "disabled") {
+ $unwanted_reply_threshold = "0";
+ }
+ $msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
+ $verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
+ $use_caps = isset($config['unbound']['use_caps']) ? "yes" : "no";
+
+ // Set up forwarding if it is configured
+ if (isset($config['unbound']['forwarding'])) {
+ $dnsservers = array();
+ if (isset($config['system']['dnsallowoverride'])) {
+ $ns = array_unique(get_nameservers());
+ foreach ($ns as $nameserver) {
+ if ($nameserver) {
+ $dnsservers[] = $nameserver;
+ }
+ }
+ } else {
+ $ns = array();
+ }
+ $sys_dnsservers = array_unique(get_dns_servers());
+ foreach ($sys_dnsservers as $sys_dnsserver) {
+ if ($sys_dnsserver && (!in_array($sys_dnsserver, $ns))) {
+ $dnsservers[] = $sys_dnsserver;
+ }
+ }
+
+ if (!empty($dnsservers)) {
+ $forward_conf .=<<<EOD
+# Forwarding
+forward-zone:
+ name: "."
+
+EOD;
+ foreach ($dnsservers as $dnsserver) {
+ $forward_conf .= "\tforward-addr: $dnsserver\n";
+ }
+ }
+ } else {
+ $forward_conf = "";
+ }
+
+ // Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
+ $rrset_cache_size = $msg_cache_size * 2;
+
+ $unboundconf = <<<EOD
+##########################
+# Unbound Configuration
+##########################
+
+##
+# Server configuration
+##
+server:
+{$reverse_zones}
+chroot: {$g['unbound_chroot_path']}
+username: "unbound"
+directory: "{$g['unbound_chroot_path']}"
+pidfile: "/var/run/unbound.pid"
+use-syslog: yes
+port: {$port}
+verbosity: {$verbosity}
+hide-identity: {$hide_identity}
+hide-version: {$hide_version}
+harden-glue: yes
+do-ip4: yes
+do-ip6: yes
+do-udp: yes
+do-tcp: yes
+do-daemonize: yes
+module-config: "{$module_config}"
+unwanted-reply-threshold: {$unwanted_reply_threshold}
+num-queries-per-thread: {$num_queries_per_thread}
+jostle-timeout: {$jostle_timeout}
+infra-host-ttl: {$infra_host_ttl}
+infra-cache-numhosts: {$infra_cache_numhosts}
+outgoing-num-tcp: {$outgoing_num_tcp}
+incoming-num-tcp: {$incoming_num_tcp}
+edns-buffer-size: {$edns_buffer_size}
+cache-max-ttl: {$cache_max_ttl}
+cache-min-ttl: {$cache_min_ttl}
+harden-dnssec-stripped: {$harden_dnssec_stripped}
+msg-cache-size: {$msg_cache_size}m
+rrset-cache-size: {$rrset_cache_size}m
+
+{$optimization['number_threads']}
+{$optimization['msg_cache_slabs']}
+{$optimization['rrset_cache_slabs']}
+{$optimization['infra_cache_slabs']}
+{$optimization['key_cache_slabs']}
+outgoing-range: 4096
+{$optimization['so_rcvbuf']}
+{$anchor_file}
+prefetch: {$prefetch}
+prefetch-key: {$prefetch_key}
+use-caps-for-id: {$use_caps}
+# Statistics
+{$statistics}
+# Interface IP(s) to bind to
+{$bindints}
+{$outgoingints}
+
+# DNS Rebinding
+{$private_addr}
+{$private_domains}
+
+# Access lists
+include: {$g['unbound_chroot_path']}/access_lists.conf
+
+# Static host entries
+include: {$g['unbound_chroot_path']}/host_entries.conf
+
+# dhcp lease entries
+include: {$g['unbound_chroot_path']}/dhcpleases_entries.conf
+
+# Domain overrides
+include: {$g['unbound_chroot_path']}/domainoverrides.conf
+{$forward_conf}
+
+{$custom_options}
+
+###
+# Remote Control Config
+###
+include: {$g['unbound_chroot_path']}/remotecontrol.conf
+
+EOD;
+
+ create_unbound_chroot_path();
+ file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
+
+ return 0;
+}
+
+function unbound_remote_control_setup() {
+ global $g;
+
+ if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
+ $remotcfg = <<<EOF
+remote-control:
+ control-enable: yes
+ control-interface: 127.0.0.1
+ control-port: 953
+ server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
+ server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
+ control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
+ control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
+
+EOF;
+
+ create_unbound_chroot_path();
+ file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
+
+ // Generate our keys
+ do_as_unbound_user("unbound-control-setup");
+
+ }
+}
+
+// Read /etc/hosts
+function read_hosts() {
+
+ /* Open /etc/hosts and extract the only dhcpleases info
+ * XXX - to convert to an unbound C library which reads /etc/hosts automatically
+ */
+ $etc_hosts = array();
+ foreach (file('/etc/hosts') as $line) {
+ if (strpos($line, "dhcpleases automatically entered")) {
+ break;
+ }
+ $d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
+ if (empty($d) || substr(reset($d), 0, 1) == "#") {
+ continue;
+ }
+ $ip = array_shift($d);
+ $fqdn = array_shift($d);
+ $name = array_shift($d);
+ if (!empty($fqdn) && $fqdn != "empty") {
+ if (!empty($name) && $name != "empty") {
+ array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
+ } else {
+ array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
+ }
+ }
+ }
+ return $etc_hosts;
+}
+
+function sync_unbound_service() {
+ global $config, $g;
+
+ create_unbound_chroot_path();
+
+ // Configure our Unbound service
+ do_as_unbound_user("unbound-anchor");
+ unbound_remote_control_setup();
+ unbound_generate_config();
+ do_as_unbound_user("start");
+ require_once("service-utils.inc");
+ if (is_service_running("unbound")) {
+ do_as_unbound_user("restore_cache");
+ }
+
+}
+
+function unbound_acl_id_used($id) {
+ global $config;
+
+ if (is_array($config['unbound']['acls'])) {
+ foreach ($config['unbound']['acls'] as & $acls) {
+ if ($id == $acls['aclid']) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function unbound_get_next_id() {
+ $aclid = 0;
+ while (unbound_acl_id_used($aclid)) {
+ $aclid++;
+ }
+ return $aclid;
+}
+
+// Execute commands as the user unbound
+function do_as_unbound_user($cmd) {
+ global $g;
+
+ switch ($cmd) {
+ case "start":
+ mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
+ break;
+ case "stop":
+ mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
+ break;
+ case "reload":
+ mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
+ break;
+ case "unbound-anchor":
+ mwexec("echo '/usr/local/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
+ break;
+ case "unbound-control-setup":
+ mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
+ break;
+ default:
+ break;
+ }
+}
+
+function unbound_add_domain_overrides($pvt_rev="") {
+ global $config, $g;
+
+ $domains = $config['unbound']['domainoverrides'];
+
+ $sorted_domains = msort($domains, "domain");
+ $result = array();
+ foreach ($sorted_domains as $domain) {
+ $domain_key = current($domain);
+ if (!isset($result[$domain_key])) {
+ $result[$domain_key] = array();
+ }
+ $result[$domain_key][] = $domain['ip'];
+ }
+
+ // Domain overrides that have multiple entries need multiple stub-addr: added
+ $domain_entries = "";
+ foreach ($result as $domain=>$ips) {
+ if ($pvt_rev == "private") {
+ $domain_entries .= "private-domain: \"$domain\"\n";
+ $domain_entries .= "domain-insecure: \"$domain\"\n";
+ } else if ($pvt_rev == "reverse") {
+ if ((substr($domain, -14) == ".in-addr.arpa.") || (substr($domain, -13) == ".in-addr.arpa")) {
+ $domain_entries .= "local-zone: \"$domain\" typetransparent\n";
+ }
+ } else {
+ $domain_entries .= "stub-zone:\n";
+ $domain_entries .= "\tname: \"$domain\"\n";
+ foreach ($ips as $ip) {
+ $domain_entries .= "\tstub-addr: $ip\n";
+ }
+ $domain_entries .= "\tstub-prime: no\n";
+ }
+ }
+
+ if ($pvt_rev != "") {
+ return $domain_entries;
+ } else {
+ create_unbound_chroot_path();
+ file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
+ }
+}
+
+function unbound_add_host_entries() {
+ global $config, $g;
+
+ $unbound_entries = "local-zone: \"{$config['system']['domain']}\" transparent\n";
+
+ $hosts = read_hosts();
+ $added_ptr = array();
+ foreach ($hosts as $host) {
+ if (is_ipaddrv4($host['ipaddr'])) {
+ $type = 'A';
+ } else if (is_ipaddrv6($host['ipaddr'])) {
+ $type = 'AAAA';
+ } else {
+ continue;
+ }
+
+ if (!$added_ptr[$host['ipaddr']]) {
+ $unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
+ $added_ptr[$host['ipaddr']] = true;
+ }
+ $unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
+ if (isset($host['name'])) {
+ $unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
+ }
+ }
+
+ // Write out entries
+ create_unbound_chroot_path();
+ file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
+
+ /* dhcpleases will write to this config file, make sure it exists */
+ @touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
+}
+
+function unbound_control($action) {
+ global $config, $g;
+
+ $cache_dumpfile = "/var/tmp/unbound_cache";
+
+ switch ($action) {
+ case "start":
+ // Start Unbound
+ if ($config['unbound']['enable'] == "on") {
+ if (!is_service_running("unbound")) {
+ do_as_unbound_user("start");
+ }
+ }
+ break;
+ case "stop":
+ if ($config['unbound']['enable'] == "on") {
+ do_as_unbound_user("stop");
+ }
+ break;
+ case "reload":
+ if ($config['unbound']['enable'] == "on") {
+ do_as_unbound_user("reload");
+ }
+ break;
+ case "dump_cache":
+ // Dump Unbound's Cache
+ if ($config['unbound']['dumpcache'] == "on") {
+ do_as_unbound_user("dump_cache");
+ }
+ break;
+ case "restore_cache":
+ // Restore Unbound's Cache
+ if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
+ if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
+ do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+}
+
+// Generation of Unbound statistics
+function unbound_statistics() {
+ global $config;
+
+ if ($config['stats'] == "on") {
+ $stats_interval = $config['unbound']['stats_interval'];
+ $cumulative_stats = $config['cumulative_stats'];
+ if ($config['extended_stats'] == "on") {
+ $extended_stats = "yes";
+ } else {
+ $extended_stats = "no";
+ }
+ } else {
+ $stats_interval = "0";
+ $cumulative_stats = "no";
+ $extended_stats = "no";
+ }
+ /* XXX To do - add RRD graphs */
+ $stats = <<<EOF
+# Unbound Statistics
+statistics-interval: {$stats_interval}
+extended-statistics: yes
+statistics-cumulative: yes
+
+EOF;
+
+ return $stats;
+}
+
+// Unbound Access lists
+function unbound_acls_config() {
+ global $g, $config;
+
+ if (!isset($config['unbound']['disable_auto_added_access_control'])) {
+ $aclcfg = "access-control: 127.0.0.1/32 allow\n";
+ $aclcfg .= "access-control: ::1 allow\n";
+ // Add our networks for active interfaces including localhost
+ if (!empty($config['unbound']['active_interface'])) {
+ $active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
+ if (in_array("all", $active_interfaces)) {
+ $active_interfaces = get_configured_interface_with_descr();
+ }
+ } else {
+ $active_interfaces = get_configured_interface_with_descr();
+ }
+
+ $bindints = "";
+ foreach ($active_interfaces as $ubif => $ifdesc) {
+ $ifip = get_interface_ip($ubif);
+ if (is_ipaddrv4($ifip)) {
+ // IPv4 is handled via NAT networks below
+ }
+ $ifip = get_interface_ipv6($ubif);
+ if (is_ipaddrv6($ifip)) {
+ if (!is_linklocal($ifip)) {
+ $subnet_bits = get_interface_subnetv6($ubif);
+ $subnet_ip = gen_subnetv6($ifip, $subnet_bits);
+ // only add LAN-type interfaces
+ if (!interface_has_gateway($ubif)) {
+ $aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
+ }
+ }
+ // add for IPv6 static routes to local networks
+ // for safety, we include only routes reachable on an interface with no
+ // gateway specified - read: not an Internet connection.
+ $static_routes = get_staticroutes();
+ foreach ($static_routes as $route) {
+ if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
+ // route is on this interface, interface doesn't have gateway, add it
+ $aclcfg .= "access-control: {$route['network']} allow\n";
+ }
+ }
+ }
+ }
+
+ // Generate IPv4 access-control entries using the same logic as automatic outbound NAT
+ if (empty($FilterIflist)) {
+ filter_generate_optcfg_array();
+ }
+ $natnetworks_array = array();
+ $natnetworks_array = filter_nat_rules_automatic_tonathosts();
+ foreach ($natnetworks_array as $allowednet) {
+ $aclcfg .= "access-control: $allowednet allow \n";
+ }
+ }
+
+ // Configure the custom ACLs
+ if (is_array($config['unbound']['acls'])) {
+ foreach ($config['unbound']['acls'] as $unbound_acl) {
+ $aclcfg .= "#{$unbound_acl['aclname']}\n";
+ foreach ($unbound_acl['row'] as $network) {
+ if ($unbound_acl['aclaction'] == "allow snoop") {
+ $unbound_acl['aclaction'] = "allow_snoop";
+ }
+ $aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
+ }
+ }
+ }
+ // Write out Access list
+ create_unbound_chroot_path();
+ file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $aclcfg);
+
+}
+
+// Generate hosts and reload services
+function unbound_hosts_generate() {
+ // Generate our hosts file
+ unbound_add_host_entries();
+
+ // Reload our service to read the updates
+ unbound_control("reload");
+}
+
+?>
diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc
new file mode 100644
index 0000000..3f14248
--- /dev/null
+++ b/src/etc/inc/upgrade_config.inc
@@ -0,0 +1,3825 @@
+<?php
+/*
+ upgrade_config.inc
+ Copyright (C) 2004-2009 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/bin/find /bin/cd /usr/local/bin/rrdtool /usr/bin/nice
+ pfSense_MODULE: config
+*/
+
+if (!function_exists("dump_rrd_to_xml")) {
+ require("rrd.inc");
+}
+
+/* Upgrade functions must be named:
+* upgrade_XXX_to_YYY
+ * where XXX == previous version, zero padded, and YYY == next version, zero padded
+ */
+function upgrade_010_to_011() {
+ global $config;
+ $opti = 1;
+ $ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
+
+ /* convert DMZ to optional, if necessary */
+ if (isset($config['interfaces']['dmz'])) {
+
+ $dmzcfg = &$config['interfaces']['dmz'];
+
+ if ($dmzcfg['if']) {
+ $config['interfaces']['opt' . $opti] = array();
+ $optcfg = &$config['interfaces']['opt' . $opti];
+
+ $optcfg['enable'] = $dmzcfg['enable'];
+ $optcfg['descr'] = "DMZ";
+ $optcfg['if'] = $dmzcfg['if'];
+ $optcfg['ipaddr'] = $dmzcfg['ipaddr'];
+ $optcfg['subnet'] = $dmzcfg['subnet'];
+
+ $ifmap['dmz'] = "opt" . $opti;
+ $opti++;
+ }
+
+ unset($config['interfaces']['dmz']);
+ }
+
+ /* convert WLAN1/2 to optional, if necessary */
+ for ($i = 1; isset($config['interfaces']['wlan' . $i]); $i++) {
+
+ if (!$config['interfaces']['wlan' . $i]['if']) {
+ unset($config['interfaces']['wlan' . $i]);
+ continue;
+ }
+
+ $wlancfg = &$config['interfaces']['wlan' . $i];
+ $config['interfaces']['opt' . $opti] = array();
+ $optcfg = &$config['interfaces']['opt' . $opti];
+
+ $optcfg['enable'] = $wlancfg['enable'];
+ $optcfg['descr'] = "WLAN" . $i;
+ $optcfg['if'] = $wlancfg['if'];
+ $optcfg['ipaddr'] = $wlancfg['ipaddr'];
+ $optcfg['subnet'] = $wlancfg['subnet'];
+ $optcfg['bridge'] = $wlancfg['bridge'];
+
+ $optcfg['wireless'] = array();
+ $optcfg['wireless']['mode'] = $wlancfg['mode'];
+ $optcfg['wireless']['ssid'] = $wlancfg['ssid'];
+ $optcfg['wireless']['channel'] = $wlancfg['channel'];
+ $optcfg['wireless']['wep'] = $wlancfg['wep'];
+
+ $ifmap['wlan' . $i] = "opt" . $opti;
+
+ unset($config['interfaces']['wlan' . $i]);
+ $opti++;
+ }
+
+ /* convert filter rules */
+ $n = count($config['filter']['rule']);
+ for ($i = 0; $i < $n; $i++) {
+
+ $fr = &$config['filter']['rule'][$i];
+
+ /* remap interface */
+ if (array_key_exists($fr['interface'], $ifmap)) {
+ $fr['interface'] = $ifmap[$fr['interface']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: filter rule removed " .
+ "(interface '%s' does not exist anymore)."), "\n", $fr['interface']);
+ unset($config['filter']['rule'][$i]);
+ continue;
+ }
+
+ /* remap source network */
+ if (isset($fr['source']['network'])) {
+ if (array_key_exists($fr['source']['network'], $ifmap)) {
+ $fr['source']['network'] = $ifmap[$fr['source']['network']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: filter rule removed " .
+ "(source network '%s' does not exist anymore)."), "\n", $fr['source']['network']);
+ unset($config['filter']['rule'][$i]);
+ continue;
+ }
+ }
+
+ /* remap destination network */
+ if (isset($fr['destination']['network'])) {
+ if (array_key_exists($fr['destination']['network'], $ifmap)) {
+ $fr['destination']['network'] = $ifmap[$fr['destination']['network']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: filter rule removed " .
+ "(destination network '%s' does not exist anymore)."), "\n", $fr['destination']['network']);
+ unset($config['filter']['rule'][$i]);
+ continue;
+ }
+ }
+ }
+
+ /* convert shaper rules */
+ $n = count($config['pfqueueing']['rule']);
+ if (is_array($config['pfqueueing']['rule'])) {
+ for ($i = 0; $i < $n; $i++) {
+
+ $fr = &$config['pfqueueing']['rule'][$i];
+
+ /* remap interface */
+ if (array_key_exists($fr['interface'], $ifmap)) {
+ $fr['interface'] = $ifmap[$fr['interface']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: traffic shaper rule removed " .
+ "(interface '%s' does not exist anymore)."), "\n", $fr['interface']);
+ unset($config['pfqueueing']['rule'][$i]);
+ continue;
+ }
+
+ /* remap source network */
+ if (isset($fr['source']['network'])) {
+ if (array_key_exists($fr['source']['network'], $ifmap)) {
+ $fr['source']['network'] = $ifmap[$fr['source']['network']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: traffic shaper rule removed " .
+ "(source network '%s' does not exist anymore)."), "\n", $fr['source']['network']);
+ unset($config['pfqueueing']['rule'][$i]);
+ continue;
+ }
+ }
+
+ /* remap destination network */
+ if (isset($fr['destination']['network'])) {
+ if (array_key_exists($fr['destination']['network'], $ifmap)) {
+ $fr['destination']['network'] = $ifmap[$fr['destination']['network']];
+ } else {
+ /* remove the rule */
+ printf(gettext("%sWarning: traffic shaper rule removed " .
+ "(destination network '%s' does not exist anymore)."), "\n", $fr['destination']['network']);
+ unset($config['pfqueueing']['rule'][$i]);
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+function upgrade_011_to_012() {
+ global $config;
+ /* move LAN DHCP server config */
+ $tmp = $config['dhcpd'];
+ $config['dhcpd'] = array();
+ $config['dhcpd']['lan'] = $tmp;
+
+ /* encrypt password */
+ $config['system']['password'] = crypt($config['system']['password']);
+}
+
+
+function upgrade_012_to_013() {
+ global $config;
+ /* convert advanced outbound NAT config */
+ for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
+ $curent = &$config['nat']['advancedoutbound']['rule'][$i];
+ $src = $curent['source'];
+ $curent['source'] = array();
+ $curent['source']['network'] = $src;
+ $curent['destination'] = array();
+ $curent['destination']['any'] = true;
+ }
+
+ /* add an explicit type="pass" to all filter rules to make things consistent */
+ for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
+ $config['filter']['rule'][$i]['type'] = "pass";
+ }
+}
+
+
+function upgrade_013_to_014() {
+ global $config;
+ /* convert shaper rules (make pipes) */
+ if (is_array($config['pfqueueing']['rule'])) {
+ $config['pfqueueing']['pipe'] = array();
+
+ for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
+ $curent = &$config['pfqueueing']['rule'][$i];
+
+ /* make new pipe and associate with this rule */
+ $newpipe = array();
+ $newpipe['descr'] = $curent['descr'];
+ $newpipe['bandwidth'] = $curent['bandwidth'];
+ $newpipe['delay'] = $curent['delay'];
+ $newpipe['mask'] = $curent['mask'];
+ $config['pfqueueing']['pipe'][$i] = $newpipe;
+
+ $curent['targetpipe'] = $i;
+
+ unset($curent['bandwidth']);
+ unset($curent['delay']);
+ unset($curent['mask']);
+ }
+ }
+}
+
+
+function upgrade_014_to_015() {
+ global $config;
+ /* Default route moved */
+ if (isset($config['interfaces']['wan']['gateway'])) {
+ if ($config['interfaces']['wan']['gateway'] <> "") {
+ $config['system']['gateway'] = $config['interfaces']['wan']['gateway'];
+ }
+ }
+ unset($config['interfaces']['wan']['gateway']);
+
+ /* Queues are no longer interface specific */
+ if (isset($config['interfaces']['lan']['schedulertype'])) {
+ unset($config['interfaces']['lan']['schedulertype']);
+ }
+ if (isset($config['interfaces']['wan']['schedulertype'])) {
+ unset($config['interfaces']['wan']['schedulertype']);
+ }
+
+ for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+ if (isset($config['interfaces']['opt' . $i]['schedulertype'])) {
+ unset($config['interfaces']['opt' . $i]['schedulertype']);
+ }
+ }
+}
+
+
+function upgrade_015_to_016() {
+ global $config;
+ /* Alternate firmware URL moved */
+ if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
+ $config['system']['alt_firmware_url'] = array();
+ $config['system']['alt_firmware_url']['enabled'] = "";
+ $config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
+ $config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
+ unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
+ } else {
+ unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
+ }
+}
+
+
+function upgrade_016_to_017() {
+ global $config;
+ /* wipe previous shaper configuration */
+ unset($config['shaper']['queue']);
+ unset($config['shaper']['rule']);
+ unset($config['interfaces']['wan']['bandwidth']);
+ unset($config['interfaces']['wan']['bandwidthtype']);
+ unset($config['interfaces']['lan']['bandwidth']);
+ unset($config['interfaces']['lan']['bandwidthtype']);
+ $config['shaper']['enable'] = FALSE;
+}
+
+
+function upgrade_017_to_018() {
+ global $config;
+ if (isset($config['proxyarp']) && is_array($config['proxyarp']['proxyarpnet'])) {
+ $proxyarp = &$config['proxyarp']['proxyarpnet'];
+ foreach ($proxyarp as $arpent) {
+ $vip = array();
+ $vip['mode'] = "proxyarp";
+ $vip['interface'] = $arpent['interface'];
+ $vip['descr'] = $arpent['descr'];
+ if (isset($arpent['range'])) {
+ $vip['range'] = $arpent['range'];
+ $vip['type'] = "range";
+ } else {
+ $subnet = explode('/', $arpent['network']);
+ $vip['subnet'] = $subnet[0];
+ if (isset($subnet[1])) {
+ $vip['subnet_bits'] = $subnet[1];
+ $vip['type'] = "network";
+ } else {
+ $vip['subnet_bits'] = "32";
+ $vip['type'] = "single";
+ }
+ }
+ $config['virtualip']['vip'][] = $vip;
+ }
+ unset($config['proxyarp']);
+ }
+ if (isset($config['installedpackages']) && isset($config['installedpackages']['carp']) && is_array($config['installedpackages']['carp']['config'])) {
+ $carp = &$config['installedpackages']['carp']['config'];
+ foreach ($carp as $carpent) {
+ $vip = array();
+ $vip['mode'] = "carp";
+ $vip['interface'] = "AUTO";
+ $vip['descr'] = sprintf(gettext("CARP vhid %s"), $carpent['vhid']);
+ $vip['type'] = "single";
+ $vip['vhid'] = $carpent['vhid'];
+ $vip['advskew'] = $carpent['advskew'];
+ $vip['password'] = $carpent['password'];
+ $vip['subnet'] = $carpent['ipaddress'];
+ $vip['subnet_bits'] = $carpent['netmask'];
+ $config['virtualip']['vip'][] = $vip;
+ }
+ unset($config['installedpackages']['carp']);
+ }
+ /* Server NAT is no longer needed */
+ unset($config['nat']['servernat']);
+
+ /* enable SSH */
+ if ($config['version'] == "1.8") {
+ $config['system']['sshenabled'] = true;
+ }
+}
+
+
+function upgrade_018_to_019() {
+ global $config;
+ $config['theme']="metallic";
+}
+
+
+function upgrade_019_to_020() {
+ global $config;
+ if (is_array($config['ipsec']['tunnel'])) {
+ reset($config['ipsec']['tunnel']);
+ while (list($index, $tunnel) = each($config['ipsec']['tunnel'])) {
+ /* Sanity check on required variables */
+ /* This fixes bogus <tunnel> entries - remnant of bug #393 */
+ if (!isset($tunnel['local-subnet']) && !isset($tunnel['remote-subnet'])) {
+ unset($config['ipsec']['tunnel'][$tunnel]);
+ }
+ }
+ }
+}
+
+function upgrade_020_to_021() {
+ global $config;
+ /* shaper scheduler moved */
+ if (isset($config['system']['schedulertype'])) {
+ $config['shaper']['schedulertype'] = $config['system']['schedulertype'];
+ unset($config['system']['schedulertype']);
+ }
+}
+
+
+function upgrade_021_to_022() {
+ global $config;
+ /* move gateway to wan interface */
+ $config['interfaces']['wan']['gateway'] = $config['system']['gateway'];
+}
+
+function upgrade_022_to_023() {
+ global $config;
+ if (isset($config['shaper'])) {
+ /* wipe previous shaper configuration */
+ unset($config['shaper']);
+ }
+}
+
+
+function upgrade_023_to_024() {
+ global $config;
+}
+
+
+function upgrade_024_to_025() {
+ global $config;
+ $config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
+ unset($config['system']['use_rrd_gateway']);
+}
+
+
+function upgrade_025_to_026() {
+ global $config;
+ $cron_item = array();
+ $cron_item['minute'] = "0";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 newsyslog";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "1,31";
+ $cron_item['hour'] = "0-5";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 adjkerntz -a";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "1";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "1";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.update_bogons.sh";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "*/60";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 sshlockout";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "1";
+ $cron_item['hour'] = "1";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.dyndns.update";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "*/60";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 virusprot";
+
+ $config['cron']['item'][] = $cron_item;
+
+ $cron_item = array();
+ $cron_item['minute'] = "*/60";
+ $cron_item['hour'] = "*";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -t 1800 snort2c";
+
+ $config['cron']['item'][] = $cron_item;
+}
+
+
+function upgrade_026_to_027() {
+ global $config;
+}
+
+
+function upgrade_027_to_028() {
+ global $config;
+}
+
+
+function upgrade_028_to_029() {
+ global $config;
+ $rule_item = array();
+ $a_filter = &$config['filter']['rule'];
+ $rule_item['interface'] = "enc0";
+ $rule_item['type'] = "pass";
+ $rule_item['source']['any'] = true;
+ $rule_item['destination']['any'] = true;
+ $rule_item['descr'] = gettext("Permit IPsec traffic.");
+ $rule_item['statetype'] = "keep state";
+ $a_filter[] = $rule_item;
+}
+
+
+function upgrade_029_to_030() {
+ global $config;
+ /* enable the rrd config setting by default */
+ $config['rrd']['enable'] = true;
+}
+
+
+function upgrade_030_to_031() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_031_to_032() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_032_to_033() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_033_to_034() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_034_to_035() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_035_to_036() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_036_to_037() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_037_to_038() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_038_to_039() {
+ global $config;
+ /* Insert upgrade code here */
+}
+
+
+function upgrade_039_to_040() {
+ global $config, $g;
+ $config['system']['webgui']['auth_method'] = "session";
+ $config['system']['webgui']['backing_method'] = "htpasswd";
+
+ if (isset ($config['system']['username'])) {
+ $config['system']['group'] = array();
+ $config['system']['group'][0]['name'] = "admins";
+ $config['system']['group'][0]['description'] = gettext("System Administrators");
+ $config['system']['group'][0]['scope'] = "system";
+ $config['system']['group'][0]['priv'] = "page-all";
+ $config['system']['group'][0]['home'] = "index.php";
+ $config['system']['group'][0]['gid'] = "110";
+
+ $config['system']['user'] = array();
+ $config['system']['user'][0]['name'] = "{$config['system']['username']}";
+ $config['system']['user'][0]['descr'] = "System Administrator";
+ $config['system']['user'][0]['scope'] = "system";
+ $config['system']['user'][0]['groupname'] = "admins";
+ $config['system']['user'][0]['password'] = "{$config['system']['password']}";
+ $config['system']['user'][0]['uid'] = "0";
+ /* Ensure that we follow what this new "admin" username should be in the session. */
+ $_SESSION["Username"] = "{$config['system']['username']}";
+
+ $config['system']['user'][0]['priv'] = array();
+ $config['system']['user'][0]['priv'][0]['id'] = "lockwc";
+ $config['system']['user'][0]['priv'][0]['name'] = "Lock webConfigurator";
+ $config['system']['user'][0]['priv'][0]['descr'] = gettext("Indicates whether this user will lock access to the webConfigurator for other users.");
+ $config['system']['user'][0]['priv'][1]['id'] = "lock-ipages";
+ $config['system']['user'][0]['priv'][1]['name'] = "Lock individual pages";
+ $config['system']['user'][0]['priv'][1]['descr'] = gettext("Indicates whether this user will lock individual HTML pages after having accessed a particular page (the lock will be freed if the user leaves or saves the page form).");
+ $config['system']['user'][0]['priv'][2]['id'] = "hasshell";
+ $config['system']['user'][0]['priv'][2]['name'] = "Has shell access";
+ $config['system']['user'][0]['priv'][2]['descr'] = gettext("Indicates whether this user is able to login for example via SSH.");
+ $config['system']['user'][0]['priv'][3]['id'] = "copyfiles";
+ $config['system']['user'][0]['priv'][3]['name'] = "Is allowed to copy files";
+ $config['system']['user'][0]['priv'][3]['descr'] = sprintf(gettext("Indicates whether this user is allowed to copy files onto the %s appliance via SCP/SFTP. If you are going to use this privilege, you must install scponly on the appliance (Hint: pkg_add -r scponly)."), $g['product_name']);
+ $config['system']['user'][0]['priv'][4]['id'] = "isroot";
+ $config['system']['user'][0]['priv'][4]['name'] = "Is root user";
+ $config['system']['user'][0]['priv'][4]['descr'] = gettext("This user is associated with the UNIX root user (you should associate this privilege only with one single user).");
+
+ $config['system']['nextuid'] = "111";
+ $config['system']['nextgid'] = "111";
+
+ /* wipe previous auth configuration */
+ unset ($config['system']['username']);
+ unset ($config['system']['password']);
+ }
+}
+
+function upgrade_040_to_041() {
+ global $config;
+ if (!$config['sysctl']) {
+ $config['sysctl']['item'] = array();
+
+ $config['sysctl']['item'][0]['tunable'] = "net.inet.tcp.blackhole";
+ $config['sysctl']['item'][0]['descr'] = gettext("Drop packets to closed TCP ports without returning a RST");
+ $config['sysctl']['item'][0]['value'] = "default";
+
+ $config['sysctl']['item'][1]['tunable'] = "net.inet.udp.blackhole";
+ $config['sysctl']['item'][1]['descr'] = gettext("Do not send ICMP port unreachable messages for closed UDP ports");
+ $config['sysctl']['item'][1]['value'] = "default";
+
+ $config['sysctl']['item'][2]['tunable'] = "net.inet.ip.random_id";
+ $config['sysctl']['item'][2]['descr'] = gettext("Randomize the ID field in IP packets (default is 0: sequential IP IDs)");
+ $config['sysctl']['item'][2]['value'] = "default";
+
+ $config['sysctl']['item'][3]['tunable'] = "net.inet.tcp.drop_synfin";
+ $config['sysctl']['item'][3]['descr'] = gettext("Drop SYN-FIN packets (breaks RFC1379, but nobody uses it anyway)");
+ $config['sysctl']['item'][3]['value'] = "default";
+
+ $config['sysctl']['item'][4]['tunable'] = "net.inet.ip.redirect";
+ $config['sysctl']['item'][4]['descr'] = gettext("Sending of IPv4 ICMP redirects");
+ $config['sysctl']['item'][4]['value'] = "default";
+
+ $config['sysctl']['item'][5]['tunable'] = "net.inet6.ip6.redirect";
+ $config['sysctl']['item'][5]['descr'] = gettext("Sending of IPv6 ICMP redirects");
+ $config['sysctl']['item'][5]['value'] = "default";
+
+ $config['sysctl']['item'][6]['tunable'] = "net.inet.tcp.syncookies";
+ $config['sysctl']['item'][6]['descr'] = gettext("Generate SYN cookies for outbound SYN-ACK packets");
+ $config['sysctl']['item'][6]['value'] = "default";
+
+ $config['sysctl']['item'][7]['tunable'] = "net.inet.tcp.recvspace";
+ $config['sysctl']['item'][7]['descr'] = gettext("Maximum incoming TCP datagram size");
+ $config['sysctl']['item'][7]['value'] = "default";
+
+ $config['sysctl']['item'][8]['tunable'] = "net.inet.tcp.sendspace";
+ $config['sysctl']['item'][8]['descr'] = gettext("Maximum outgoing TCP datagram size");
+ $config['sysctl']['item'][8]['value'] = "default";
+
+ $config['sysctl']['item'][9]['tunable'] = "net.inet.ip.fastforwarding";
+ $config['sysctl']['item'][9]['descr'] = gettext("Fastforwarding (see http://lists.freebsd.org/pipermail/freebsd-net/2004-January/002534.html)");
+ $config['sysctl']['item'][9]['value'] = "default";
+
+ $config['sysctl']['item'][10]['tunable'] = "net.inet.tcp.delayed_ack";
+ $config['sysctl']['item'][10]['descr'] = gettext("Do not delay ACK to try and piggyback it onto a data packet");
+ $config['sysctl']['item'][10]['value'] = "default";
+
+ $config['sysctl']['item'][11]['tunable'] = "net.inet.udp.maxdgram";
+ $config['sysctl']['item'][11]['descr'] = gettext("Maximum outgoing UDP datagram size");
+ $config['sysctl']['item'][11]['value'] = "default";
+
+ $config['sysctl']['item'][12]['tunable'] = "net.link.bridge.pfil_onlyip";
+ $config['sysctl']['item'][12]['descr'] = gettext("Handling of non-IP packets which are not passed to pfil (see if_bridge(4))");
+ $config['sysctl']['item'][12]['value'] = "default";
+
+ $config['sysctl']['item'][13]['tunable'] = "net.link.tap.user_open";
+ $config['sysctl']['item'][13]['descr'] = gettext("Allow unprivileged access to tap(4) device nodes");
+ $config['sysctl']['item'][13]['value'] = "default";
+
+ $config['sysctl']['item'][15]['tunable'] = "kern.randompid";
+ $config['sysctl']['item'][15]['descr'] = gettext("Randomize PID's (see src/sys/kern/kern_fork.c: sysctl_kern_randompid())");
+ $config['sysctl']['item'][15]['value'] = "default";
+
+ $config['sysctl']['item'][16]['tunable'] = "net.inet.tcp.inflight.enable";
+ $config['sysctl']['item'][16]['descr'] = gettext("The system will attempt to calculate the bandwidth delay product for each connection and limit the amount of data queued to the network to just the amount required to maintain optimum throughput. ");
+ $config['sysctl']['item'][16]['value'] = "default";
+
+ $config['sysctl']['item'][17]['tunable'] = "net.inet.icmp.icmplim";
+ $config['sysctl']['item'][17]['descr'] = gettext("Set ICMP Limits");
+ $config['sysctl']['item'][17]['value'] = "default";
+
+ $config['sysctl']['item'][18]['tunable'] = "net.inet.tcp.tso";
+ $config['sysctl']['item'][18]['descr'] = gettext("TCP Offload engine");
+ $config['sysctl']['item'][18]['value'] = "default";
+
+ $config['sysctl']['item'][19]['tunable'] = "net.inet.ip.portrange.first";
+ $config['sysctl']['item'][19]['descr'] = "Set the ephemeral port range starting port";
+ $config['sysctl']['item'][19]['value'] = "default";
+
+ $config['sysctl']['item'][20]['tunable'] = "hw.syscons.kbd_reboot";
+ $config['sysctl']['item'][20]['descr'] = "Enables ctrl+alt+delete";
+ $config['sysctl']['item'][20]['value'] = "default";
+
+ $config['sysctl']['item'][21]['tunable'] = "kern.ipc.maxsockbuf";
+ $config['sysctl']['item'][21]['descr'] = "Maximum socket buffer size";
+ $config['sysctl']['item'][21]['value'] = "default";
+
+ }
+}
+
+
+function upgrade_041_to_042() {
+ global $config;
+ if (isset($config['shaper'])) {
+ unset($config['shaper']);
+ }
+ if (isset($config['ezshaper'])) {
+ unset($config['ezshaper']);
+ }
+}
+
+
+function upgrade_042_to_043() {
+ global $config;
+ /* migrate old interface gateway to the new gateways config */
+ $iflist = get_configured_interface_list(false, true);
+ $gateways = array();
+ $i = 0;
+ foreach ($iflist as $ifname => $interface) {
+ if (!interface_has_gateway($ifname)) {
+ continue;
+ }
+ $config['gateways']['gateway_item'][$i] = array();
+ if (is_ipaddr($config['interfaces'][$ifname]['gateway'])) {
+ $config['gateways']['gateway_item'][$i]['gateway'] = $config['interfaces'][$ifname]['gateway'];
+ $config['gateways']['gateway_item'][$i]['descr'] = sprintf(gettext("Interface %s Static Gateway"), $ifname);
+ } else {
+ $config['gateways']['gateway_item'][$i]['gateway'] = "dynamic";
+ $config['gateways']['gateway_item'][$i]['descr'] = sprintf(gettext("Interface %s Dynamic Gateway"), $ifname);
+ }
+ $config['gateways']['gateway_item'][$i]['interface'] = $ifname;
+ $config['gateways']['gateway_item'][$i]['name'] = "GW_" . strtoupper($ifname);
+ /* add default gateway bit for wan on upgrade */
+ if ($ifname == "wan") {
+ $config['gateways']['gateway_item'][$i]['defaultgw'] = true;
+ }
+ if (is_ipaddr($config['interfaces'][$ifname]['use_rrd_gateway'])) {
+ $config['gateways']['gateway_item'][$i]['monitor'] = $config['interfaces'][$ifname]['use_rrd_gateway'];
+ unset($config['interfaces'][$ifname]['use_rrd_gateway']);
+ }
+ $config['interfaces'][$ifname]['gateway'] = $config['gateways']['gateway_item'][$i]['name'];
+
+ /* Update all filter rules which might reference this gateway */
+ $j = 0;
+ foreach ($config['filter']['rule'] as $rule) {
+ if (is_ipaddr($rule['gateway'])) {
+ if ($rule['gateway'] == $config['gateways']['gateway_item'][$i]['gateway']) {
+ $config['filter']['rule'][$j]['gateway'] = $config['gateways']['gateway_item'][$i]['name'];
+ } else if ($rule['gateway'] == $ifname) {
+ $config['filter']['rule'][$j]['gateway'] = $config['gateways']['gateway_item'][$i]['name'];
+ }
+ }
+ $j++;
+ }
+
+ /* rename old Quality RRD files in the process */
+ $rrddbpath = "/var/db/rrd";
+ $gwname = "GW_" . strtoupper($ifname);
+ if (is_readable("{$rrddbpath}/{$ifname}-quality.rrd")) {
+ rename("{$rrddbpath}/{$ifname}-quality.rrd", "{$rrddbpath}/{$gwname}-quality.rrd");
+ }
+ $i++;
+ }
+}
+
+
+function upgrade_043_to_044() {
+ global $config;
+
+ /* migrate static routes to the new gateways config */
+ $gateways = return_gateways_array(true);
+ $i = 0;
+ if (is_array($config['staticroutes']['route'])) {
+ $gwmap = array();
+ foreach ($config['staticroutes']['route'] as $idx => $sroute) {
+ $found = false;
+ foreach ($gateways as $gwname => $gw) {
+ if ($gw['gateway'] == $sroute['gateway']) {
+ $config['staticroutes']['route'][$idx]['gateway'] = $gwname;
+ $found = true;
+ break;
+ }
+ }
+ if ($gwmap[$sroute['gateway']]) {
+ /* We already added a gateway name for this IP */
+ $config['staticroutes']['route'][$idx]['gateway'] = "{$gwmap[$sroute['gateway']]}";
+ $found = true;
+ }
+
+ if ($found == false) {
+ $gateway = array();
+ $gateway['name'] = "SROUTE{$i}";
+ $gwmap[$sroute['gateway']] = $gateway['name'];
+ $gateway['gateway'] = $sroute['gateway'];
+ $gateway['interface'] = $sroute['interface'];
+ $gateway['descr'] = sprintf(gettext("Upgraded static route for %s"), $sroute['network']);
+ if (!is_array($config['gateways']['gateway_item'])) {
+ $config['gateways']['gateway_item'] = array();
+ }
+ $config['gateways']['gateway_item'][] = $gateway;
+ $config['staticroutes']['route'][$idx]['gateway'] = $gateway['name'];
+ $i++;
+ }
+ }
+ }
+}
+
+
+function upgrade_044_to_045() {
+ global $config;
+ $iflist = get_configured_interface_list(false, true);
+ if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
+ $i = 0;
+ foreach ($config['vlans']['vlan'] as $id => $vlan) {
+ /* Make sure to update the interfaces section with the right name */
+ $vlan_name = "{$vlan['if']}_vlan{$vlan['tag']}";
+ foreach ($iflist as $ifname) {
+ if ($config['interfaces'][$ifname]['if'] == "vlan{$i}") {
+ $config['interfaces'][$ifname]['if'] = $vlan_name;
+ continue;
+ }
+ }
+ $config['vlans']['vlan'][$i]['vlanif'] = "{$vlan_name}";
+ $i++;
+ }
+ }
+}
+
+
+function upgrade_045_to_046() {
+ global $config;
+ /* Load up monitors that are in the default config for 2.0 but not in 1.2.3
+ thus wouldn't be in an upgraded config. */
+ $config['load_balancer']['monitor_type'] = array (
+ array ('name' => 'ICMP',
+ 'type' => 'icmp',
+ 'descr' => 'ICMP',
+ 'options' => '',
+ ),
+ array ('name' => 'TCP',
+ 'type' => 'tcp',
+ 'descr' => 'Generic TCP',
+ 'options' => '',
+ ),
+ array ('name' => 'HTTP',
+ 'type' => 'http',
+ 'descr' => 'Generic HTTP',
+ 'options' =>
+ array ('path' => '/',
+ 'host' => '',
+ 'code' => '200',
+ ),
+ ),
+ array ('name' => 'HTTPS',
+ 'type' => 'https',
+ 'descr' => 'Generic HTTPS',
+ 'options' =>
+ array ('path' => '/',
+ 'host' => '',
+ 'code' => '200',
+ ),
+ ),
+ array ('name' => 'SMTP',
+ 'type' => 'send',
+ 'descr' => 'Generic SMTP',
+ 'options' =>
+ array ('send' => '',
+ 'expect' => '220 *',
+ ),
+ ),
+ );
+ /* Upgrade load balancer from slb to relayd */
+ if (is_array($config['load_balancer']['virtual_server']) && count($config['load_balancer']['virtual_server'])) {
+ $vs_a = &$config['load_balancer']['virtual_server'];
+ $pool_a = &$config['load_balancer']['lbpool'];
+ $pools = array();
+ /* Index pools by name */
+ if (is_array($pool_a)) {
+ for ($i = 0; isset($pool_a[$i]); $i++) {
+ if ($pool_a[$i]['type'] == "server") {
+ $pools[$pool_a[$i]['name']] = $pool_a[$i];
+ }
+ }
+ }
+ /* Convert sitedown entries to pools and re-attach */
+ for ($i = 0; isset($vs_a[$i]); $i++) {
+ /* Set mode while we're here. */
+ $vs_a[$i]['mode'] = "redirect_mode";
+ if (isset($vs_a[$i]['sitedown'])) {
+ $pool = array();
+ $pool['type'] = 'server';
+ $pool['behaviour'] = 'balance';
+ $pool['name'] = "{$vs_a[$i]['name']}-sitedown";
+ $pool['descr'] = sprintf(gettext("Sitedown pool for VS: %s"), $vs_a[$i]['name']);
+ if (is_array($vs_a[$i]['pool'])) {
+ $vs_a[$i]['pool'] = $vs_a[$i]['pool'][0];
+ }
+ $pool['port'] = $pools[$vs_a[$i]['pool']]['port'];
+ $pool['servers'] = array();
+ $pool['servers'][] = $vs_a[$i]['sitedown'];
+ $pool['monitor'] = $pools[$vs_a[$i]['pool']]['monitor'];
+ $pool_a[] = $pool;
+ $vs_a[$i]['sitedown'] = $pool['name'];
+ }
+ }
+ }
+ if (count($config['load_balancer']) == 0) {
+ unset($config['load_balancer']);
+ }
+ mwexec('/usr/sbin/pw groupadd -n _relayd -g 913');
+ mwexec('/usr/sbin/pw useradd -n _relayd -c "Relay Daemon" -d /var/empty -s /usr/sbin/nologin -u 913 -g 913');
+}
+
+
+function upgrade_046_to_047() {
+ global $config;
+ /* Upgrade IPsec from tunnel to phase1/phase2 */
+
+ if (is_array($config['ipsec']['tunnel'])) {
+
+ $a_phase1 = array();
+ $a_phase2 = array();
+ $ikeid = 0;
+
+ foreach ($config['ipsec']['tunnel'] as $tunnel) {
+
+ unset($ph1ent);
+ unset($ph2ent);
+
+ /*
+ * attempt to locate an enabled phase1
+ * entry that matches the peer gateway
+ */
+
+ if (!isset($tunnel['disabled'])) {
+
+ $remote_gateway = $tunnel['remote-gateway'];
+
+ foreach ($a_phase1 as $ph1tmp) {
+ if ($ph1tmp['remote-gateway'] == $remote_gateway) {
+ $ph1ent = $ph1tmp;
+ break;
+ }
+ }
+ }
+
+ /* none found, create a new one */
+
+ if (!isset($ph1ent)) {
+
+ /* build new phase1 entry */
+
+ $ph1ent = array();
+
+ $ph1ent['ikeid'] = ++$ikeid;
+
+ if (isset($tunnel['disabled'])) {
+ $ph1ent['disabled'] = $tunnel['disabled'];
+ }
+
+ /* convert to the new vip[$vhid] name */
+ if (preg_match("/^carp/", $tunnel['interface'])) {
+ $carpid = str_replace("carp", "", $tunnel['interface']);
+ $tunnel['interface'] = "vip" . $config['virtualip']['vip'][$carpid]['vhid'];
+ }
+ $ph1ent['interface'] = $tunnel['interface'];
+ $ph1ent['remote-gateway'] = $tunnel['remote-gateway'];
+ $ph1ent['descr'] = $tunnel['descr'];
+
+ $ph1ent['mode'] = $tunnel['p1']['mode'];
+
+ if (isset($tunnel['p1']['myident']['myaddress'])) {
+ $ph1ent['myid_type'] = "myaddress";
+ }
+ if (isset($tunnel['p1']['myident']['address'])) {
+ $ph1ent['myid_type'] = "address";
+ $ph1ent['myid_data'] = $tunnel['p1']['myident']['address'];
+ }
+ if (isset($tunnel['p1']['myident']['fqdn'])) {
+ $ph1ent['myid_type'] = "fqdn";
+ $ph1ent['myid_data'] = $tunnel['p1']['myident']['fqdn'];
+ }
+ if (isset($tunnel['p1']['myident']['ufqdn'])) {
+ $ph1ent['myid_type'] = "user_fqdn";
+ $ph1ent['myid_data'] = $tunnel['p1']['myident']['ufqdn'];
+ }
+ if (isset($tunnel['p1']['myident']['asn1dn'])) {
+ $ph1ent['myid_type'] = "asn1dn";
+ $ph1ent['myid_data'] = $tunnel['p1']['myident']['asn1dn'];
+ }
+ if (isset($tunnel['p1']['myident']['dyn_dns'])) {
+ $ph1ent['myid_type'] = "dyn_dns";
+ $ph1ent['myid_data'] = $tunnel['p1']['myident']['dyn_dns'];
+ }
+
+ $ph1ent['peerid_type'] = "peeraddress";
+
+ switch ($tunnel['p1']['encryption-algorithm']) {
+ case "des":
+ $ph1alg = array('name' => 'des');
+ break;
+ case "3des":
+ $ph1alg = array('name' => '3des');
+ break;
+ case "blowfish":
+ $ph1alg = array('name' => 'blowfish', 'keylen' => '128');
+ break;
+ case "cast128":
+ $ph1alg = array('name' => 'cast128');
+ break;
+ case "rijndael":
+ $ph1alg = array('name' => 'aes', 'keylen' => '128');
+ break;
+ case "rijndael 256":
+ case "aes 256":
+ $ph1alg = array('name' => 'aes', 'keylen' => '256');
+ break;
+ }
+
+ $ph1ent['encryption-algorithm'] = $ph1alg;
+ $ph1ent['hash-algorithm'] = $tunnel['p1']['hash-algorithm'];
+ $ph1ent['dhgroup'] = $tunnel['p1']['dhgroup'];
+ $ph1ent['lifetime'] = $tunnel['p1']['lifetime'];
+ $ph1ent['authentication_method'] = $tunnel['p1']['authentication_method'];
+
+ if (isset($tunnel['p1']['pre-shared-key'])) {
+ $ph1ent['pre-shared-key'] = $tunnel['p1']['pre-shared-key'];
+ }
+ if (isset($tunnel['p1']['cert'])) {
+ $ph1ent['cert'] = $tunnel['p1']['cert'];
+ }
+ if (isset($tunnel['p1']['peercert'])) {
+ $ph1ent['peercert'] = $tunnel['p1']['peercert'];
+ }
+ if (isset($tunnel['p1']['private-key'])) {
+ $ph1ent['private-key'] = $tunnel['p1']['private-key'];
+ }
+
+ $ph1ent['nat_traversal'] = "on";
+ $ph1ent['dpd_enable'] = 1;
+ $ph1ent['dpd_delay'] = 10;
+ $ph1ent['dpd_maxfail'] = 5;
+
+ $a_phase1[] = $ph1ent;
+ }
+
+ /* build new phase2 entry */
+
+ $ph2ent = array();
+
+ $ph2ent['ikeid'] = $ph1ent['ikeid'];
+
+ if (isset($tunnel['disabled'])) {
+ $ph1ent['disabled'] = $tunnel['disabled'];
+ }
+
+ $ph2ent['descr'] = sprintf(gettext("phase2 for %s"), $tunnel['descr']);
+
+ $type = "lan";
+ if ($tunnel['local-subnet']['network']) {
+ $type = $tunnel['local-subnet']['network'];
+ }
+ if ($tunnel['local-subnet']['address']) {
+ list($address, $netbits) = explode("/", $tunnel['local-subnet']['address']);
+ if (is_null($netbits)) {
+ $type = "address";
+ } else {
+ $type = "network";
+ }
+ }
+
+ switch ($type) {
+ case "address":
+ $ph2ent['localid'] = array('type' => $type, 'address' => $address);
+ break;
+ case "network":
+ $ph2ent['localid'] = array('type' => $type, 'address' => $address, 'netbits' => $netbits);
+ break;
+ default:
+ $ph2ent['localid'] = array('type' => $type);
+ break;
+ }
+
+ list($address, $netbits) = explode("/", $tunnel['remote-subnet']);
+ $ph2ent['remoteid'] = array('type' => 'network', 'address' => $address, 'netbits' => $netbits);
+
+ $ph2ent['protocol'] = $tunnel['p2']['protocol'];
+
+ $aes_count = 0;
+ foreach ($tunnel['p2']['encryption-algorithm-option'] as $tunalg) {
+ $aes_found = false;
+ switch ($tunalg) {
+ case "des":
+ $ph2alg = array('name' => 'des');
+ break;
+ case "3des":
+ $ph2alg = array('name' => '3des');
+ break;
+ case "blowfish":
+ $ph2alg = array('name' => 'blowfish', 'keylen' => 'auto');
+ break;
+ case "cast128":
+ $ph2alg = array('name' => 'cast128');
+ break;
+ case "rijndael":
+ case "rijndael 256":
+ case "aes 256":
+ $ph2alg = array('name' => 'aes', 'keylen' => 'auto');
+ $aes_found = true;
+ $aes_count++;
+ break;
+ }
+
+ if (!$aes_found || ($aes_count < 2)) {
+ $ph2ent['encryption-algorithm-option'][] = $ph2alg;
+ }
+ }
+
+ $ph2ent['hash-algorithm-option'] = $tunnel['p2']['hash-algorithm-option'];
+ $ph2ent['pfsgroup'] = $tunnel['p2']['pfsgroup'];
+ $ph2ent['lifetime'] = $tunnel['p2']['lifetime'];
+
+ if (isset($tunnel['pinghost']['pinghost'])) {
+ $ph2ent['pinghost'] = $tunnel['pinghost'];
+ }
+
+ $a_phase2[] = $ph2ent;
+ }
+
+ unset($config['ipsec']['tunnel']);
+ $config['ipsec']['phase1'] = $a_phase1;
+ $config['ipsec']['phase2'] = $a_phase2;
+ }
+
+ /* Upgrade Mobile IPsec */
+ if (isset($config['ipsec']['mobileclients']) &&
+ is_array($config['ipsec']['mobileclients']) &&
+ is_array($config['ipsec']['mobileclients']['p1']) &&
+ is_array($config['ipsec']['mobileclients']['p2'])) {
+
+ if (isset($config['ipsec']['mobileclients']['enable'])) {
+ $config['ipsec']['client']['enable'] = true;
+ $config['ipsec']['client']['user_source'] = 'system';
+ $config['ipsec']['client']['group_source'] = 'system';
+ }
+
+ $mobilecfg = $config['ipsec']['mobileclients'];
+
+ $ph1ent = array();
+ $ph1ent['ikeid'] = ++$ikeid;
+
+ if (!isset($mobilecfg['enable'])) {
+ $ph1ent['disabled'] = true;
+ }
+
+ /* Assume WAN since mobile tunnels couldn't be on a separate interface on 1.2.x */
+ $ph1ent['interface'] = 'wan';
+ $ph1ent['descr'] = "Mobile Clients (upgraded)";
+ $ph1ent['mode'] = $mobilecfg['p1']['mode'];
+
+ if (isset($mobilecfg['p1']['myident']['myaddress'])) {
+ $ph1ent['myid_type'] = "myaddress";
+ }
+ if (isset($mobilecfg['p1']['myident']['address'])) {
+ $ph1ent['myid_type'] = "address";
+ $ph1ent['myid_data'] = $mobilecfg['p1']['myident']['address'];
+ }
+ if (isset($mobilecfg['p1']['myident']['fqdn'])) {
+ $ph1ent['myid_type'] = "fqdn";
+ $ph1ent['myid_data'] = $mobilecfg['p1']['myident']['fqdn'];
+ }
+ if (isset($mobilecfg['p1']['myident']['ufqdn'])) {
+ $ph1ent['myid_type'] = "user_fqdn";
+ $ph1ent['myid_data'] = $mobilecfg['p1']['myident']['ufqdn'];
+ }
+ if (isset($mobilecfg['p1']['myident']['asn1dn'])) {
+ $ph1ent['myid_type'] = "asn1dn";
+ $ph1ent['myid_data'] = $mobilecfg['p1']['myident']['asn1dn'];
+ }
+ if (isset($mobilecfg['p1']['myident']['dyn_dns'])) {
+ $ph1ent['myid_type'] = "dyn_dns";
+ $ph1ent['myid_data'] = $mobilecfg['p1']['myident']['dyn_dns'];
+ }
+ $ph1ent['peerid_type'] = "fqdn";
+ $ph1ent['peerid_data'] = "";
+
+ switch ($mobilecfg['p1']['encryption-algorithm']) {
+ case "des":
+ $ph1alg = array('name' => 'des');
+ break;
+ case "3des":
+ $ph1alg = array('name' => '3des');
+ break;
+ case "blowfish":
+ $ph1alg = array('name' => 'blowfish', 'keylen' => '128');
+ break;
+ case "cast128":
+ $ph1alg = array('name' => 'cast128');
+ break;
+ case "rijndael":
+ $ph1alg = array('name' => 'aes', 'keylen' => '128');
+ break;
+ case "rijndael 256":
+ case "aes 256":
+ $ph1alg = array('name' => 'aes', 'keylen' => '256');
+ break;
+ }
+
+ $ph1ent['encryption-algorithm'] = $ph1alg;
+ $ph1ent['hash-algorithm'] = $mobilecfg['p1']['hash-algorithm'];
+ $ph1ent['dhgroup'] = $mobilecfg['p1']['dhgroup'];
+ $ph1ent['lifetime'] = $mobilecfg['p1']['lifetime'];
+ $ph1ent['authentication_method'] = $mobilecfg['p1']['authentication_method'];
+
+ if (isset($mobilecfg['p1']['cert'])) {
+ $ph1ent['cert'] = $mobilecfg['p1']['cert'];
+ }
+ if (isset($mobilecfg['p1']['peercert'])) {
+ $ph1ent['peercert'] = $mobilecfg['p1']['peercert'];
+ }
+ if (isset($mobilecfg['p1']['private-key'])) {
+ $ph1ent['private-key'] = $mobilecfg['p1']['private-key'];
+ }
+
+ $ph1ent['nat_traversal'] = "on";
+ $ph1ent['dpd_enable'] = 1;
+ $ph1ent['dpd_delay'] = 10;
+ $ph1ent['dpd_maxfail'] = 5;
+ $ph1ent['mobile'] = true;
+
+ $ph2ent = array();
+ $ph2ent['ikeid'] = $ph1ent['ikeid'];
+ $ph2ent['descr'] = "phase2 for ".$mobilecfg['descr'];
+ $ph2ent['localid'] = array('type' => 'none');
+ $ph2ent['remoteid'] = array('type' => 'mobile');
+ $ph2ent['protocol'] = $mobilecfg['p2']['protocol'];
+
+ $aes_count = 0;
+ foreach ($mobilecfg['p2']['encryption-algorithm-option'] as $tunalg) {
+ $aes_found = false;
+ switch ($tunalg) {
+ case "des":
+ $ph2alg = array('name' => 'des');
+ break;
+ case "3des":
+ $ph2alg = array('name' => '3des');
+ break;
+ case "blowfish":
+ $ph2alg = array('name' => 'blowfish', 'keylen' => 'auto');
+ break;
+ case "cast128":
+ $ph2alg = array('name' => 'cast128');
+ break;
+ case "rijndael":
+ case "rijndael 256":
+ case "aes 256":
+ $ph2alg = array('name' => 'aes', 'keylen' => 'auto');
+ $aes_found = true;
+ $aes_count++;
+ break;
+ }
+
+ if (!$aes_found || ($aes_count < 2)) {
+ $ph2ent['encryption-algorithm-option'][] = $ph2alg;
+ }
+ }
+ $ph2ent['hash-algorithm-option'] = $mobilecfg['p2']['hash-algorithm-option'];
+ $ph2ent['pfsgroup'] = $mobilecfg['p2']['pfsgroup'];
+ $ph2ent['lifetime'] = $mobilecfg['p2']['lifetime'];
+ $ph2ent['mobile'] = true;
+
+ $config['ipsec']['phase1'][] = $ph1ent;
+ $config['ipsec']['phase2'][] = $ph2ent;
+ unset($config['ipsec']['mobileclients']);
+ }
+}
+
+
+function upgrade_047_to_048() {
+ global $config;
+ if (!empty($config['dyndns'])) {
+ $config['dyndnses'] = array();
+ $config['dyndnses']['dyndns'] = array();
+ if (isset($config['dyndns'][0]['host'])) {
+ $tempdyn = array();
+ $tempdyn['enable'] = isset($config['dyndns'][0]['enable']);
+ $tempdyn['type'] = $config['dyndns'][0]['type'];
+ $tempdyn['wildcard'] = isset($config['dyndns'][0]['wildcard']);
+ $tempdyn['username'] = $config['dyndns'][0]['username'];
+ $tempdyn['password'] = $config['dyndns'][0]['password'];
+ $tempdyn['host'] = $config['dyndns'][0]['host'];
+ $tempdyn['mx'] = $config['dyndns'][0]['mx'];
+ $tempdyn['interface'] = "wan";
+ $tempdyn['descr'] = sprintf(gettext("Upgraded Dyndns %s"), $tempdyn['type']);
+ $config['dyndnses']['dyndns'][] = $tempdyn;
+ }
+ unset($config['dyndns']);
+ }
+ if (!empty($config['dnsupdate'])) {
+ $pconfig = $config['dnsupdate'][0];
+ if (!$pconfig['ttl']) {
+ $pconfig['ttl'] = 60;
+ }
+ if (!$pconfig['keytype']) {
+ $pconfig['keytype'] = "zone";
+ }
+ $pconfig['interface'] = "wan";
+ $config['dnsupdates']['dnsupdate'][] = $pconfig;
+ unset($config['dnsupdate']);
+ }
+
+ if (is_array($config['pppoe']) && is_array($config['pppoe'][0])) {
+ $pconfig = array();
+ $pconfig['username'] = $config['pppoe'][0]['username'];
+ $pconfig['password'] = $config['pppoe'][0]['password'];
+ $pconfig['provider'] = $config['pppoe'][0]['provider'];
+ $pconfig['ondemand'] = isset($config['pppoe'][0]['ondemand']);
+ $pconfig['timeout'] = $config['pppoe'][0]['timeout'];
+ unset($config['pppoe']);
+ $config['interfaces']['wan']['pppoe_username'] = $pconfig['username'];
+ $config['interfaces']['wan']['pppoe_password'] = $pconfig['password'];
+ $config['interfaces']['wan']['provider'] = $pconfig['provider'];
+ $config['interfaces']['wan']['ondemand'] = isset($pconfig['ondemand']);
+ $config['interfaces']['wan']['timeout'] = $pconfig['timeout'];
+ }
+ if (is_array($config['pptp'])) {
+ $pconfig = array();
+ $pconfig['username'] = $config['pptp']['username'];
+ $pconfig['password'] = $config['pptp']['password'];
+ $pconfig['provider'] = $config['pptp']['provider'];
+ $pconfig['ondemand'] = isset($config['pptp']['ondemand']);
+ $pconfig['timeout'] = $config['pptp']['timeout'];
+ unset($config['pptp']);
+ $config['interfaces']['wan']['pptp_username'] = $pconfig['username'];
+ $config['interfaces']['wan']['pptp_password'] = $pconfig['password'];
+ $config['interfaces']['wan']['provider'] = $pconfig['provider'];
+ $config['interfaces']['wan']['ondemand'] = isset($pconfig['ondemand']);
+ $config['interfaces']['wan']['timeout'] = $pconfig['timeout'];
+ }
+}
+
+
+function upgrade_048_to_049() {
+ global $config;
+ /* setup new all users group */
+ $all = array();
+ $all['name'] = "all";
+ $all['description'] = gettext("All Users");
+ $all['scope'] = "system";
+ $all['gid'] = 1998;
+ $all['member'] = array();
+
+ if (!is_array($config['system']['user'])) {
+ $config['system']['user'] = array();
+ }
+ if (!is_array($config['system']['group'])) {
+ $config['system']['group'] = array();
+ }
+
+ /* work around broken uid assignments */
+ $config['system']['nextuid'] = 2000;
+ foreach ($config['system']['user'] as & $user) {
+ if (isset($user['uid']) && !$user['uid']) {
+ continue;
+ }
+ $user['uid'] = $config['system']['nextuid']++;
+ }
+
+ /* work around broken gid assignments */
+ $config['system']['nextgid'] = 2000;
+ foreach ($config['system']['group'] as & $group) {
+ if ($group['name'] == $g['admin_group']) {
+ $group['gid'] = 1999;
+ } else {
+ $group['gid'] = $config['system']['nextgid']++;
+ }
+ }
+
+ /* build group membership information */
+ foreach ($config['system']['group'] as & $group) {
+ $group['member'] = array();
+ foreach ($config['system']['user'] as & $user) {
+ $groupnames = explode(",", $user['groupname']);
+ if (in_array($group['name'], $groupnames)) {
+ $group['member'][] = $user['uid'];
+ }
+ }
+ }
+
+ /* reset user group information */
+ foreach ($config['system']['user'] as & $user) {
+ unset($user['groupname']);
+ $all['member'][] = $user['uid'];
+ }
+
+ /* reset group scope information */
+ foreach ($config['system']['group'] as & $group) {
+ if ($group['name'] != $g['admin_group']) {
+ $group['scope'] = "user";
+ }
+ }
+
+ /* insert new all group */
+ $groups = Array();
+ $groups[] = $all;
+ $groups = array_merge($config['system']['group'], $groups);
+ $config['system']['group'] = $groups;
+}
+
+
+function upgrade_049_to_050() {
+ global $config;
+
+ if (!is_array($config['system']['user'])) {
+ $config['system']['user'] = array();
+ }
+ /* update user privileges */
+ foreach ($config['system']['user'] as & $user) {
+ $privs = array();
+ if (!is_array($user['priv'])) {
+ unset($user['priv']);
+ continue;
+ }
+ foreach ($user['priv'] as $priv) {
+ switch ($priv['id']) {
+ case "hasshell":
+ $privs[] = "user-shell-access";
+ break;
+ case "copyfiles":
+ $privs[] = "user-copy-files";
+ break;
+ }
+ }
+ $user['priv'] = $privs;
+ }
+
+ /* update group privileges */
+ foreach ($config['system']['group'] as & $group) {
+ $privs = array();
+ if (!is_array($group['pages'])) {
+ unset($group['pages']);
+ continue;
+ }
+ foreach ($group['pages'] as $page) {
+ $priv = map_page_privname($page);
+ if ($priv) {
+ $privs[] = $priv;
+ }
+ }
+ unset($group['pages']);
+ $group['priv'] = $privs;
+ }
+
+ /* sync all local account information */
+ local_sync_accounts();
+}
+
+
+function upgrade_050_to_051() {
+ global $config;
+ $pconfig = array();
+ $pconfig['descr'] = "Set to 0 to disable filtering on the incoming and outgoing member interfaces.";
+ $pconfig['tunable'] = "net.link.bridge.pfil_member";
+ $pconfig['value'] = "1";
+ $config['sysctl']['item'][] = $pconfig;
+ $pconfig = array();
+ $pconfig['descr'] = "Set to 1 to enable filtering on the bridge interface";
+ $pconfig['tunable'] = "net.link.bridge.pfil_bridge";
+ $pconfig['value'] = "0";
+ $config['sysctl']['item'][] = $pconfig;
+
+ unset($config['bridge']);
+
+ $convert_bridges = false;
+ foreach ($config['interfaces'] as $intf) {
+ if (isset($intf['bridge']) && $intf['bridge'] <> "") {
+ $config['bridges'] = array();
+ $config['bridges']['bridged'] = array();
+ $convert_bridges = true;
+ break;
+ }
+ }
+ if ($convert_bridges == true) {
+ $i = 0;
+ foreach ($config['interfaces'] as $ifr => &$intf) {
+ if (isset($intf['bridge']) && $intf['bridge'] <> "") {
+ $nbridge = array();
+ $nbridge['members'] = "{$ifr},{$intf['bridge']}";
+ $nbridge['descr'] = sprintf(gettext("Converted bridged %s"), $ifr);
+ $nbridge['bridgeif'] = "bridge{$i}";
+ $config['bridges']['bridged'][] = $nbridge;
+ unset($intf['bridge']);
+ $i++;
+ }
+ }
+ }
+}
+
+
+function upgrade_051_to_052() {
+ global $config;
+ $config['openvpn'] = array();
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+
+ $vpnid = 1;
+
+ /* openvpn server configurations */
+ if (is_array($config['installedpackages']['openvpnserver'])) {
+ $config['openvpn']['openvpn-server'] = array();
+
+ $index = 1;
+ foreach ($config['installedpackages']['openvpnserver']['config'] as $server) {
+
+ if (!is_array($server)) {
+ continue;
+ }
+
+ if ($server['auth_method'] == "pki") {
+
+ /* create ca entry */
+ $ca = array();
+ $ca['refid'] = uniqid();
+ $ca['descr'] = "OpenVPN Server CA #{$index}";
+ $ca['crt'] = $server['ca_cert'];
+ $config['ca'][] = $ca;
+
+ /* create ca reference */
+ unset($server['ca_cert']);
+ $server['caref'] = $ca['refid'];
+
+ /* create a crl entry if needed */
+ if (!empty($server['crl'][0])) {
+ $crl = array();
+ $crl['refid'] = uniqid();
+ $crl['descr'] = "Imported OpenVPN CRL #{$index}";
+ $crl['caref'] = $ca['refid'];
+ $crl['text'] = $server['crl'][0];
+ if (!is_array($config['crl'])) {
+ $config['crl'] = array();
+ }
+ $config['crl'][] = $crl;
+ $server['crlref'] = $crl['refid'];
+ }
+ unset($server['crl']);
+
+ /* create cert entry */
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = "OpenVPN Server Certificate #{$index}";
+ $cert['crt'] = $server['server_cert'];
+ $cert['prv'] = $server['server_key'];
+ $config['cert'][] = $cert;
+
+ /* create cert reference */
+ unset($server['server_cert']);
+ unset($server['server_key']);
+ $server['certref'] = $cert['refid'];
+
+ $index++;
+ }
+
+ /* determine operational mode */
+ if ($server['auth_method'] == 'pki') {
+ if ($server['nopool']) {
+ $server['mode'] = "p2p_tls";
+ } else {
+ $server['mode'] = "server_tls";
+ }
+ } else {
+ $server['mode'] = "p2p_shared_key";
+ }
+ unset($server['auth_method']);
+
+ /* modify configuration values */
+ $server['dh_length'] = 1024;
+ unset($server['dh_params']);
+ if (!$server['interface']) {
+ $server['interface'] = 'any';
+ }
+ $server['tunnel_network'] = $server['addresspool'];
+ unset($server['addresspool']);
+ if (isset($server['use_lzo']) && ($server['use_lzo'] == "on")) {
+ $server['compression'] = "on";
+ unset($server['use_lzo']);
+ }
+ if ($server['nopool']) {
+ $server['pool_enable'] = false;
+ } else {
+ $server['pool_enable'] = "yes";
+ }
+ unset($server['nopool']);
+ $server['dns_domain'] = $server['dhcp_domainname'];
+ unset($server['dhcp_domainname']);
+
+ $tmparr = explode(";", $server['dhcp_dns'], 4);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $server["dns_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($server['dhcp_dns']);
+
+ $tmparr = explode(";", $server['dhcp_ntp'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $server["ntp_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($server['dhcp_ntp']);
+
+ if ($server['dhcp_nbtdisable']) {
+ $server['netbios_enable'] = false;
+ } else {
+ $server['netbios_enable'] = "yes";
+ }
+ unset($server['dhcp_nbtdisable']);
+ $server['netbios_ntype'] = $server['dhcp_nbttype'];
+ unset($server['dhcp_nbttype']);
+ $server['netbios_scope'] = $server['dhcp_nbtscope'];
+ unset($server['dhcp_nbtscope']);
+
+ $tmparr = explode(";", $server['dhcp_nbdd'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $server["nbdd_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($server['dhcp_nbdd']);
+
+ $tmparr = explode(";", $server['dhcp_wins'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $server["wins_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($server['dhcp_wins']);
+
+ if (!empty($server['disable'])) {
+ $server['disable'] = true;
+ } else {
+ unset($server['disable']);
+ }
+
+ /* allocate vpnid */
+ $server['vpnid'] = $vpnid++;
+
+ if (!empty($server['custom_options'])) {
+ $cstmopts = array();
+ $tmpcstmopts = explode(";", $server['custom_options']);
+ $assigned_if = "";
+ $tmpstr = "";
+ foreach ($tmpcstmopts as $tmpcstmopt) {
+ $tmpstr = str_replace(" ", "", $tmpcstmopt);
+ if (substr($tmpstr, 0, 6) == "devtun") {
+ $assigned_if = substr($tmpstr, 3);
+ continue;
+ } else if (substr($tmpstr, 0, 5) == "local") {
+ $localip = substr($tmpstr, 5);
+ $server['ipaddr'] = str_replace("\n", "", $localip);
+ } else {
+ $cstmopts[] = $tmpcstmopt;
+ }
+ }
+ $server['custom_options'] = implode(";", $cstmopts);
+ if (!empty($assigned_if)) {
+ foreach ($config['interfaces'] as $iface => $cfgif) {
+ if ($cfgif['if'] == $assigned_if) {
+ $config['interfaces'][$iface]['if'] = "ovpns{$server['vpnid']}";
+ break;
+ }
+ }
+ }
+ }
+
+ $config['openvpn']['openvpn-server'][] = $server;
+ }
+ unset($config['installedpackages']['openvpnserver']);
+ }
+
+ /* openvpn client configurations */
+ if (is_array($config['installedpackages']['openvpnclient'])) {
+ $config['openvpn']['openvpn-client'] = array();
+
+ $index = 1;
+ foreach ($config['installedpackages']['openvpnclient']['config'] as $client) {
+
+ if (!is_array($client)) {
+ continue;
+ }
+
+ if ($client['auth_method'] == "pki") {
+
+ /* create ca entry */
+ $ca = array();
+ $ca['refid'] = uniqid();
+ $ca['descr'] = "OpenVPN Client CA #{$index}";
+ $ca['crt'] = $client['ca_cert'];
+ $ca['crl'] = $client['crl'];
+ $config['ca'][] = $ca;
+
+ /* create ca reference */
+ unset($client['ca_cert']);
+ unset($client['crl']);
+ $client['caref'] = $ca['refid'];
+
+ /* create cert entry */
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = "OpenVPN Client Certificate #{$index}";
+ $cert['crt'] = $client['client_cert'];
+ $cert['prv'] = $client['client_key'];
+ $config['cert'][] = $cert;
+
+ /* create cert reference */
+ unset($client['client_cert']);
+ unset($client['client_key']);
+ $client['certref'] = $cert['refid'];
+
+ $index++;
+ }
+
+ /* determine operational mode */
+ if ($client['auth_method'] == 'pki') {
+ $client['mode'] = "p2p_tls";
+ } else {
+ $client['mode'] = "p2p_shared_key";
+ }
+ unset($client['auth_method']);
+
+ /* modify configuration values */
+ if (!$client['interface']) {
+ $client['interface'] = 'wan';
+ }
+ $client['tunnel_network'] = $client['interface_ip'];
+ unset($client['interface_ip']);
+ $client['server_addr'] = $client['serveraddr'];
+ unset($client['serveraddr']);
+ $client['server_port'] = $client['serverport'];
+ unset($client['serverport']);
+ $client['proxy_addr'] = $client['poxy_hostname'];
+ unset($client['proxy_addr']);
+ if (isset($client['use_lzo']) && ($client['use_lzo'] == "on")) {
+ $client['compression'] = "on";
+ unset($client['use_lzo']);
+ }
+ $client['resolve_retry'] = $client['infiniteresolvretry'];
+ unset($client['infiniteresolvretry']);
+
+ /* allocate vpnid */
+ $client['vpnid'] = $vpnid++;
+
+ if (!empty($client['custom_options'])) {
+ $cstmopts = array();
+ $tmpcstmopts = explode(";", $client['custom_options']);
+ $assigned_if = "";
+ $tmpstr = "";
+ foreach ($tmpcstmopts as $tmpcstmopt) {
+ $tmpstr = str_replace(" ", "", $tmpcstmopt);
+ if (substr($tmpstr, 0, 6) == "devtun") {
+ $assigned_if = substr($tmpstr, 3);
+ continue;
+ } else if (substr($tmpstr, 0, 5) == "local") {
+ $localip = substr($tmpstr, 5);
+ $client['ipaddr'] = str_replace("\n", "", $localip);
+ } else {
+ $cstmopts[] = $tmpcstmopt;
+ }
+ }
+ $client['custom_options'] = implode(";", $cstmopts);
+ if (!empty($assigned_if)) {
+ foreach ($config['interfaces'] as $iface => $cfgif) {
+ if ($cfgif['if'] == $assigned_if) {
+ $config['interfaces'][$iface]['if'] = "ovpnc{$client['vpnid']}";
+ break;
+ }
+ }
+ }
+ }
+
+ if (!empty($client['disable'])) {
+ $client['disable'] = true;
+ } else {
+ unset($client['disable']);
+ }
+
+ $config['openvpn']['openvpn-client'][] = $client;
+ }
+
+ unset($config['installedpackages']['openvpnclient']);
+ }
+
+ /* openvpn client specific configurations */
+ if (is_array($config['installedpackages']['openvpncsc'])) {
+ $config['openvpn']['openvpn-csc'] = array();
+
+ foreach ($config['installedpackages']['openvpncsc']['config'] as $csc) {
+
+ if (!is_array($csc)) {
+ continue;
+ }
+
+ /* modify configuration values */
+ $csc['common_name'] = $csc['commonname'];
+ unset($csc['commonname']);
+ $csc['tunnel_network'] = $csc['ifconfig_push'];
+ unset($csc['ifconfig_push']);
+ $csc['dns_domain'] = $csc['dhcp_domainname'];
+ unset($csc['dhcp_domainname']);
+
+ $tmparr = explode(";", $csc['dhcp_dns'], 4);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $csc["dns_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($csc['dhcp_dns']);
+
+ $tmparr = explode(";", $csc['dhcp_ntp'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $csc["ntp_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($csc['dhcp_ntp']);
+
+ if ($csc['dhcp_nbtdisable']) {
+ $csc['netbios_enable'] = false;
+ } else {
+ $csc['netbios_enable'] = "yes";
+ }
+ unset($csc['dhcp_nbtdisable']);
+ $csc['netbios_ntype'] = $csc['dhcp_nbttype'];
+ unset($csc['dhcp_nbttype']);
+ $csc['netbios_scope'] = $csc['dhcp_nbtscope'];
+ unset($csc['dhcp_nbtscope']);
+
+ $tmparr = explode(";", $csc['dhcp_nbdd'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $csc["nbdd_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($csc['dhcp_nbdd']);
+
+ $tmparr = explode(";", $csc['dhcp_wins'], 2);
+ $d=1;
+ foreach ($tmparr as $tmpa) {
+ $csc["wins_server{$d}"] = $tmpa;
+ $d++;
+ }
+ unset($csc['dhcp_wins']);
+
+ if (!empty($csc['disable'])) {
+ $csc['disable'] = true;
+ } else {
+ unset($csc['disable']);
+ }
+
+ $config['openvpn']['openvpn-csc'][] = $csc;
+ }
+
+ unset($config['installedpackages']['openvpncsc']);
+ }
+
+ if (count($config['openvpn']['openvpn-server']) > 0 ||
+ count($config['openvpn']['openvpn-client']) > 0) {
+ $ovpnrule = array();
+ $ovpnrule['type'] = "pass";
+ $ovpnrule['interface'] = "openvpn";
+ $ovpnrule['statetype'] = "keep state";
+ $ovpnrule['source'] = array();
+ $ovpnrule['destination'] = array();
+ $ovpnrule['source']['any'] = true;
+ $ovpnrule['destination']['any'] = true;
+ $ovpnrule['descr'] = gettext("Auto added OpenVPN rule from config upgrade.");
+ $config['filter']['rule'][] = $ovpnrule;
+ }
+
+ /*
+ * FIXME: hack to keep things working with no installedpackages
+ * or carp array in the configuration data.
+ */
+ if (!is_array($config['installedpackages'])) {
+ $config['installedpackages'] = array();
+ }
+ if (!is_array($config['installedpackages']['carp'])) {
+ $config['installedpackages']['carp'] = array();
+ }
+
+}
+
+
+function upgrade_052_to_053() {
+ global $config;
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+
+ /* migrate advanced admin page webui ssl to certificate manager */
+ if ($config['system']['webgui']['certificate'] &&
+ $config['system']['webgui']['private-key']) {
+
+ /* create cert entry */
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = "webConfigurator SSL Certificate";
+ $cert['crt'] = $config['system']['webgui']['certificate'];
+ $cert['prv'] = $config['system']['webgui']['private-key'];
+ $config['cert'][] = $cert;
+
+ /* create cert reference */
+ unset($config['system']['webgui']['certificate']);
+ unset($config['system']['webgui']['private-key']);
+ $config['system']['webgui']['ssl-certref'] = $cert['refid'];
+ }
+
+ /* migrate advanced admin page ssh keys to user manager */
+ if ($config['system']['ssh']['authorizedkeys']) {
+ $admin_user =& getUserEntryByUID(0);
+ $admin_user['authorizedkeys'] = $config['system']['ssh']['authorizedkeys'];
+ unset($config['system']['ssh']['authorizedkeys']);
+ }
+}
+
+
+function upgrade_053_to_054() {
+ global $config;
+ if (is_array($config['load_balancer']['lbpool'])) {
+ $lbpool_arr = $config['load_balancer']['lbpool'];
+ $lbpool_srv_arr = array();
+ $gateway_group_arr = array();
+ $gateways = return_gateways_array();
+ $group_name_changes = array();
+ if (!is_array($config['gateways']['gateway_item'])) {
+ $config['gateways']['gateway_item'] = array();
+ }
+
+ $a_gateways =& $config['gateways']['gateway_item'];
+ foreach ($lbpool_arr as $lbpool) {
+ if ($lbpool['type'] == "gateway") {
+ // Gateway Groups have to have valid names in pf, old lb pools did not. Clean them up.
+ $group_name = preg_replace("/[^A-Za-z0-9]/", "", $lbpool['name']);
+ // If we made and changes, check for collisions and note the change.
+ if ($group_name != $lbpool['name']) {
+ // Make sure the name isn't already in use.
+ foreach ($gateway_group_arr as $gwg) {
+ // If the name is in use, add some random bits to avoid collision.
+ if ($gwg['name'] == $group_name) {
+ $group_name .= uniqid();
+ }
+ }
+ $group_name_changes[$lbpool['name']] = $group_name;
+ }
+ $gateway_group['name'] = $group_name;
+ $gateway_group['descr'] = $lbpool['descr'];
+ $gateway_group['trigger'] = "down";
+ $gateway_group['item'] = array();
+ $i = 0;
+ foreach ($lbpool['servers'] as $member) {
+ $split = explode("|", $member);
+ $interface = $split[0];
+ $monitor = $split[1];
+ /* on static upgraded configuration we automatically prepend GW_ */
+ $static_name = "GW_" . strtoupper($interface);
+ if (is_ipaddr($monitor)) {
+ foreach ($a_gateways as & $gw) {
+ if ($gw['name'] == $static_name) {
+ $gw['monitor'] = $monitor;
+ }
+ }
+ }
+
+ /* on failover increment tier. Else always assign 1 */
+ if ($lbpool['behaviour'] == "failover") {
+ $i++;
+ } else {
+ $i = 1;
+ }
+ $gateway_group['item'][] = "$static_name|$i";
+ }
+ $gateway_group_arr[] = $gateway_group;
+ } else {
+ $lbpool_srv_arr[] = $lbpool;
+ }
+ }
+ $config['load_balancer']['lbpool'] = $lbpool_srv_arr;
+ $config['gateways']['gateway_group'] = $gateway_group_arr;
+ }
+ // Unset lbpool if we no longer have any server pools
+ if (count($lbpool_srv_arr) == 0) {
+ if (empty($config['load_balancer'])) {
+ unset($config['load_balancer']);
+ } else {
+ unset($config['load_balancer']['lbpool']);
+ }
+ } else {
+ $config['load_balancer']['lbpool'] = $lbpool_srv_arr;
+ }
+ // Only set the gateway group array if we converted any
+ if (count($gateway_group_arr) != 0) {
+ $config['gateways']['gateway_group'] = $gateway_group_arr;
+ // Update any rules that had a gateway change, if any.
+ if (count($group_name_changes) > 0) {
+ foreach ($config['filter']['rule'] as & $rule) {
+ if (!empty($rule["gateway"]) && array_key_exists($rule["gateway"], $group_name_changes)) {
+ $rule["gateway"] = $group_name_changes[$rule["gateway"]];
+ }
+ }
+ }
+ }
+}
+
+
+function upgrade_054_to_055() {
+ global $config;
+ global $g;
+
+ /* RRD files changed for quality, traffic and packets graphs */
+ //ini_set("max_execution_time", "1800");
+ /* convert traffic RRD file */
+ global $parsedcfg, $listtags;
+ $listtags = array("ds", "v", "rra", "row");
+
+ $rrddbpath = "/var/db/rrd/";
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+ if ($g['platform'] != "pfSense") {
+ /* restore the databases, if we have one */
+ if (restore_rrd()) {
+ /* Make sure to move the rrd backup out of the way. We will make a new one after converting. */
+ @rename("{$g['cf_conf_path']}/rrd.tgz", "{$g['cf_conf_path']}/backup/rrd.tgz");
+ }
+ }
+
+ $rrdinterval = 60;
+ $valid = $rrdinterval * 2;
+
+ /* Asume GigE for now */
+ $downstream = 125000000;
+ $upstream = 125000000;
+
+ /* build a list of quality databases */
+ /* roundtrip has become delay */
+ function divide_delay($delayval) {
+ $delayval = floatval($delayval);
+ $delayval = ($delayval / 1000);
+ $delayval = " ". sprintf("%1.10e", $delayval) ." ";
+ return $delayval;
+ }
+ /* the roundtrip times need to be divided by 1000 to get seconds, really */
+ $databases = array();
+ if (!file_exists($rrddbpath)) {
+ @mkdir($rrddbpath);
+ }
+ chdir($rrddbpath);
+ $databases = glob("*-quality.rrd");
+ rsort($databases);
+ foreach ($databases as $database) {
+ $xmldump = "{$database}.old.xml";
+ $xmldumpnew = "{$database}.new.xml";
+
+ if (platform_booting()) {
+ echo "Migrate RRD database {$database} to new format for IPv6 \n";
+ }
+ mwexec("$rrdtool tune {$rrddbpath}{$database} -r roundtrip:delay 2>&1");
+
+ dump_rrd_to_xml("{$rrddbpath}/{$database}", "{$g['tmp_path']}/{$xmldump}");
+ $rrdold = xml2array(file_get_contents("{$g['tmp_path']}/{$xmldump}"), 1, "tag");
+ $rrdold = $rrdold['rrd'];
+
+ $i = 0;
+ foreach ($rrdold['rra'] as $rra) {
+ $l = 0;
+ foreach ($rra['database']['row'] as $row) {
+ $vnew = divide_delay($row['v'][1]);
+ $rrdold['rra'][$i]['database']['row'][$l]['v'][1] = $vnew;
+ $l++;
+ }
+ $i++;
+ }
+
+ file_put_contents("{$g['tmp_path']}/{$xmldumpnew}", dump_xml_config_raw($rrdold, "rrd"));
+ mwexec("$rrdtool restore -f {$g['tmp_path']}/{$xmldumpnew} {$rrddbpath}/{$database} 2>&1");
+
+ unset($rrdold);
+ @unlink("{$g['tmp_path']}/{$xmldump}");
+ @unlink("{$g['tmp_path']}/{$xmldumpnew}");
+ }
+ /* let apinger recreate required files */
+ if (!platform_booting()) {
+ setup_gateways_monitor();
+ }
+
+ /* build a list of traffic and packets databases */
+ $databases = return_dir_as_array($rrddbpath, '/-(traffic|packets)\.rrd$/');
+ rsort($databases);
+ foreach ($databases as $database) {
+ $databasetmp = "{$database}.tmp";
+ $xmldump = "{$database}.old.xml";
+ $xmldumptmp = "{$database}.tmp.xml";
+ $xmldumpnew = "{$database}.new.xml";
+
+ if (platform_booting()) {
+ echo "Migrate RRD database {$database} to new format \n";
+ }
+ /* rename DS source */
+ mwexec("$rrdtool tune {$rrddbpath}/{$database} -r in:inpass 2>&1");
+ mwexec("$rrdtool tune {$rrddbpath}/{$database} -r out:outpass 2>71");
+
+ /* dump contents to xml and move database out of the way */
+ dump_rrd_to_xml("{$rrddbpath}/{$database}", "{$g['tmp_path']}/{$xmldump}");
+
+ /* create new rrd database file */
+ $rrdcreate = "$rrdtool create {$g['tmp_path']}/{$databasetmp} --step $rrdinterval ";
+ $rrdcreate .= "DS:inpass:COUNTER:$valid:0:$downstream ";
+ $rrdcreate .= "DS:outpass:COUNTER:$valid:0:$upstream ";
+ $rrdcreate .= "DS:inblock:COUNTER:$valid:0:$downstream ";
+ $rrdcreate .= "DS:outblock:COUNTER:$valid:0:$upstream ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:1:1000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:5:1000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:60:1000 ";
+ $rrdcreate .= "RRA:AVERAGE:0.5:720:1000 ";
+
+ create_new_rrd("$rrdcreate");
+ /* create temporary xml from new RRD */
+ dump_rrd_to_xml("{$g['tmp_path']}/{$databasetmp}", "{$g['tmp_path']}/{$xmldumptmp}");
+
+ $rrdold = xml2array(file_get_contents("{$g['tmp_path']}/{$xmldump}"), 1, "tag");
+ $rrdold = $rrdold['rrd'];
+
+ $rrdnew = xml2array(file_get_contents("{$g['tmp_path']}/{$xmldumptmp}"), 1, "tag");
+ $rrdnew = $rrdnew['rrd'];
+
+ /* remove any MAX RRA's. Not needed for traffic. */
+ $i = 0;
+ foreach ($rrdold['rra'] as $rra) {
+ if (trim($rra['cf']) == "MAX") {
+ unset($rrdold['rra'][$i]);
+ }
+ $i++;
+ }
+
+ file_put_contents("{$g['tmp_path']}/{$xmldumpnew}", dump_xml_config_raw(migrate_rrd_format($rrdold, $rrdnew), "rrd"));
+ mwexec("$rrdtool restore -f {$g['tmp_path']}/{$xmldumpnew} {$rrddbpath}/{$database} 2>&1");
+ /* we now have the rrd with the new fields, adjust the size now. */
+ /* RRA 2 is 60 minutes, RRA 3 is 720 minutes */
+ mwexec("/bin/sync");
+ mwexec("$rrdtool resize {$rrddbpath}/{$database} 2 GROW 2000;/bin/mv resize.rrd {$rrddbpath}/{$database} 2>&1");
+ mwexec("/bin/sync");
+ mwexec("$rrdtool resize {$rrddbpath}/{$database} 3 GROW 2000;/bin/mv resize.rrd {$rrddbpath}/{$database} 2>&1");
+ unset($rrdxmlarray);
+ @unlink("{$g['tmp_path']}/{$xmldump}");
+ @unlink("{$g['tmp_path']}/{$xmldumpnew}");
+ }
+ if (!platform_booting()) {
+ enable_rrd_graphing();
+ }
+ /* Let's save the RRD graphs after we run enable RRD graphing */
+ /* The function will restore the rrd.tgz so we will save it after */
+ exec("cd /; LANG=C NO_REMOUNT=1 RRDDBPATH='{$rrddbpath}' CF_CONF_PATH='{$g['cf_conf_path']}' /etc/rc.backup_rrd.sh");
+ unlink_if_exists("{$g['vardb_path']}/rrd/*.xml");
+ if (platform_booting()) {
+ echo "Updating configuration...";
+ }
+}
+
+
+function upgrade_055_to_056() {
+ global $config;
+
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+
+ /* migrate ipsec ca's to cert manager */
+ if (is_array($config['ipsec']['cacert'])) {
+ foreach ($config['ipsec']['cacert'] as & $cacert) {
+ $ca = array();
+ $ca['refid'] = uniqid();
+ if (is_array($cacert['cert'])) {
+ $ca['crt'] = $cacert['cert'][0];
+ } else {
+ $ca['crt'] = $cacert['cert'];
+ }
+ $ca['descr'] = $cacert['ident'];
+ $config['ca'][] = $ca;
+ }
+ unset($config['ipsec']['cacert']);
+ }
+
+ /* migrate phase1 certificates to cert manager */
+ if (is_array($config['ipsec']['phase1'])) {
+ foreach ($config['ipsec']['phase1'] as & $ph1ent) {
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = "IPsec Peer {$ph1ent['remote-gateway']} Certificate";
+ if (is_array($ph1ent['cert'])) {
+ $cert['crt'] = $ph1ent['cert'][0];
+ } else {
+ $cert['crt'] = $ph1ent['cert'];
+ }
+ $cert['prv'] = $ph1ent['private-key'];
+ $config['cert'][] = $cert;
+ $ph1ent['certref'] = $cert['refid'];
+ if ($ph1ent['cert']) {
+ unset($ph1ent['cert']);
+ }
+ if ($ph1ent['private-key']) {
+ unset($ph1ent['private-key']);
+ }
+ if ($ph1ent['peercert']) {
+ unset($ph1ent['peercert']);
+ }
+ }
+ }
+}
+
+
+function upgrade_056_to_057() {
+ global $config;
+
+ if (!is_array($config['system']['user'])) {
+ $config['system']['user'] = array();
+ }
+ /* migrate captivate portal to user manager */
+ if (is_array($config['captiveportal']['user'])) {
+ foreach ($config['captiveportal']['user'] as $user) {
+ // avoid user conflicts
+ $found = false;
+ foreach ($config['system']['user'] as $userent) {
+ if ($userent['name'] == $user['name']) {
+ $found = true;
+ break;
+ }
+ }
+ if ($found) {
+ continue;
+ }
+ $user['scope'] = "user";
+ if (isset($user['expirationdate'])) {
+ $user['expires'] = $user['expirationdate'];
+ unset($user['expirationdate']);
+ }
+ if (isset($user['password'])) {
+ $user['md5-hash'] = $user['password'];
+ unset($user['password']);
+ }
+ $user['uid'] = $config['system']['nextuid']++;
+ $config['system']['user'][] = $user;
+ }
+ unset($config['captiveportal']['user']);
+ }
+}
+
+function upgrade_057_to_058() {
+ global $config;
+ /* set all phase2 entries to tunnel mode */
+ if (is_array($config['ipsec']['phase2'])) {
+ foreach ($config['ipsec']['phase2'] as & $ph2ent) {
+ $ph2ent['mode'] = 'tunnel';
+ }
+ }
+}
+
+function upgrade_058_to_059() {
+ global $config;
+
+ if (is_array($config['schedules']['schedule'])) {
+ foreach ($config['schedules']['schedule'] as & $schedl) {
+ $schedl['schedlabel'] = uniqid();
+ }
+ }
+}
+
+function upgrade_059_to_060() {
+ global $config;
+ require_once("/etc/inc/certs.inc");
+ if (is_array($config['ca'])) {
+ /* Locate issuer for all CAs */
+ foreach ($config['ca'] as & $ca) {
+ $subject = cert_get_subject($ca['crt']);
+ $issuer = cert_get_issuer($ca['crt']);
+ if ($issuer <> $subject) {
+ $issuer_crt =& lookup_ca_by_subject($issuer);
+ if ($issuer_crt) {
+ $ca['caref'] = $issuer_crt['refid'];
+ }
+ }
+ }
+
+ /* Locate issuer for all certificates */
+ if (is_array($config['cert'])) {
+ foreach ($config['cert'] as & $cert) {
+ $subject = cert_get_subject($cert['crt']);
+ $issuer = cert_get_issuer($cert['crt']);
+ if ($issuer <> $subject) {
+ $issuer_crt =& lookup_ca_by_subject($issuer);
+ if ($issuer_crt) {
+ $cert['caref'] = $issuer_crt['refid'];
+ }
+ }
+ }
+ }
+ }
+}
+
+function upgrade_060_to_061() {
+ global $config;
+
+ if (is_array($config['interfaces']['wan'])) {
+ $config['interfaces']['wan']['enable'] = true;
+ }
+ if (is_array($config['interfaces']['lan'])) {
+ $config['interfaces']['lan']['enable'] = true;
+ }
+
+ /* On 1.2.3 the "mtu" field adjusted MSS.
+ On 2.x the "mtu" field is actually the MTU. Rename accordingly.
+ See redmine ticket #1886
+ */
+ foreach ($config['interfaces'] as $ifr => &$intf) {
+ if (isset($intf['mtu']) && is_numeric($intf['mtu'])) {
+ $intf['mss'] = $intf['mtu'];
+ unset($intf['mtu']);
+ }
+ }
+}
+
+function upgrade_061_to_062() {
+ global $config;
+
+ /* Convert NAT port forwarding rules */
+ if (is_array($config['nat']['rule'])) {
+ $a_nat = &$config['nat']['rule'];
+
+ foreach ($a_nat as &$natent) {
+ $natent['disabled'] = false;
+ $natent['nordr'] = false;
+
+ $natent['source'] = array(
+ "not" => false,
+ "any" => true,
+ "port" => ""
+ );
+
+ $natent['destination'] = array(
+ "not" => false,
+ "address" => $natent['external-address'],
+ "port" => $natent['external-port']
+ );
+
+ if (empty($natent['destination']['address'])) {
+ unset($natent['destination']['address']);
+ $natent['destination']['network'] = $natent['interface'] . 'ip';
+ } else if ($natent['destination']['address'] == 'any') {
+ unset($natent['destination']['address']);
+ $natent['destination']['any'] = true;
+ }
+
+ unset($natent['external-address']);
+ unset($natent['external-port']);
+ }
+
+ unset($natent);
+ }
+}
+
+function upgrade_062_to_063() {
+ /* Upgrade legacy Themes to the new pfsense_ng */
+ global $config;
+
+ switch ($config['theme']) {
+ case "nervecenter":
+ $config['theme'] = "pfsense_ng";
+ break;
+ }
+
+}
+
+function upgrade_063_to_064() {
+ global $config;
+ $j = 0;
+ $ifcfg = &$config['interfaces'];
+
+ if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
+ $config['ppps']['ppp'][$pppid]['if'] = "ppp".$j;
+ $config['ppps']['ppp'][$pppid]['ptpid'] = $j;
+ $j++;
+ if (isset($ppp['port'])) {
+ $config['ppps']['ppp'][$pppid]['ports'] = $ppp['port'];
+ unset($config['ppps']['ppp'][$pppid]['port']);
+ }
+ if (!isset($ppp['type'])) {
+ $config['ppps']['ppp'][$pppid]['type'] = "ppp";
+ }
+ if (isset($ppp['defaultgw'])) {
+ unset($config['ppps']['ppp'][$pppid]['defaultgw']);
+ }
+ }
+ }
+
+ if (!is_array($config['ppps']['ppp'])) {
+ $config['ppps']['ppp'] = array();
+ }
+ $a_ppps = &$config['ppps']['ppp'];
+
+ foreach ($ifcfg as $ifname => $ifinfo) {
+ $ppp = array();
+ // For pppoe conversion
+ if ($ifinfo['ipaddr'] == "pppoe" || $ifinfo['ipaddr'] == "pptp") {
+ if (isset($ifinfo['ptpid'])) {
+ continue;
+ }
+ $ppp['ptpid'] = $j;
+ $ppp['type'] = $ifinfo['ipaddr'];
+ $ppp['if'] = $ifinfo['ipaddr'].$j;
+ $ppp['ports'] = $ifinfo['if'];
+ if ($ifinfo['ipaddr'] == "pppoe") {
+ $ppp['username'] = $ifinfo['pppoe_username'];
+ $ppp['password'] = base64_encode($ifinfo['pppoe_password']);
+ }
+ if ($ifinfo['ipaddr'] == "pptp") {
+ $ppp['username'] = $ifinfo['pptp_username'];
+ $ppp['password'] = base64_encode($ifinfo['pptp_password']);
+ }
+
+ if (isset($ifinfo['provider'])) {
+ $ppp['provider'] = $ifinfo['provider'];
+ }
+ if (isset($ifinfo['ondemand'])) {
+ $ppp['ondemand'] = true;
+ }
+ if (isset($ifinfo['timeout'])) {
+ $ppp['idletimeout'] = $ifinfo['timeout'];
+ }
+ if (isset($ifinfo['pppoe']['pppoe-reset-type'])) {
+ $ppp['pppoe-reset-type'] = $ifinfo['pppoe']['pppoe-reset-type'];
+ if (is_array($config['cron']['item'])) {
+ for ($i = 0; $i < count($config['cron']['item']); $i++) {
+ $item = $config['cron']['item'][$i];
+ if (strpos($item['command'], "/conf/pppoe{$ifname}restart") !== false) {
+ $config['cron']['item'][$i]['command'] = "/var/etc/pppoe_restart_" . $ppp['if'];
+ }
+ }
+ }
+ }
+ if (isset($ifinfo['local'])) {
+ $ppp['localip'] = $ifinfo['local'];
+ }
+ if (isset($ifinfo['subnet'])) {
+ $ppp['subnet'] = $ifinfo['subnet'];
+ }
+ if (isset($ifinfo['remote'])) {
+ $ppp['gateway'] = $ifinfo['remote'];
+ }
+
+ $ifcfg[$ifname]['if'] = $ifinfo['ipaddr'].$j;
+ $j++;
+
+ unset($ifcfg[$ifname]['pppoe_username']);
+ unset($ifcfg[$ifname]['pppoe_password']);
+ unset($ifcfg[$ifname]['provider']);
+ unset($ifcfg[$ifname]['ondemand']);
+ unset($ifcfg[$ifname]['timeout']);
+ unset($ifcfg[$ifname]['pppoe_reset']);
+ unset($ifcfg[$ifname]['pppoe_preset']);
+ unset($ifcfg[$ifname]['pppoe']);
+ unset($ifcfg[$ifname]['pptp_username']);
+ unset($ifcfg[$ifname]['pptp_password']);
+ unset($ifcfg[$ifname]['local']);
+ unset($ifcfg[$ifname]['subnet']);
+ unset($ifcfg[$ifname]['remote']);
+
+ $a_ppps[] = $ppp;
+
+ }
+ }
+}
+
+function upgrade_064_to_065() {
+ /* Disable TSO and LRO in upgraded configs */
+ global $config;
+ $config['system']['disablesegmentationoffloading'] = true;
+ $config['system']['disablelargereceiveoffloading'] = true;
+}
+
+function upgrade_065_to_066() {
+ global $config;
+
+ $dhcrelaycfg =& $config['dhcrelay'];
+
+ if (is_array($dhcrelaycfg)) {
+ $dhcrelayifs = array();
+ $foundifs = false;
+ /* DHCPRelay enabled on any interfaces? */
+ foreach ($dhcrelaycfg as $dhcrelayif => $dhcrelayifconf) {
+ if (isset($dhcrelayifconf['enable'])) {
+ $dhcrelayifs[] = $dhcrelayif;
+ unset($dhcrelaycfg['dhcrelayif']);
+ $foundifs = true;
+ }
+ }
+ if ($foundifs == true) {
+ $dhcrelaycfg['interface'] = implode(",", $dhcrelayifs);
+ }
+ }
+}
+
+function upgrade_066_to_067() {
+ global $config;
+ if (isset($config['system']['ca'])) {
+ $config['ca'] = $config['system']['ca'];
+ unset($config['system']['ca']);
+ }
+ if (isset($config['system']['cert'])) {
+ $config['cert'] = $config['system']['cert'];
+ unset($config['system']['cert']);
+ }
+}
+
+function upgrade_067_to_068() {
+ global $config;
+
+ if (!empty($config['pppoe'])) {
+ $config['pppoes'] = array();
+ $config['pppoes']['pppoe'] = array();
+ $config['pppoes']['pppoe'][] = $config['pppoe'][0];
+
+ if (is_array($config['pppoe']['user'])) {
+ $username = array();
+ foreach ($config['pppoe']['user'] as $user) {
+ $usr = $user['name'] . ":" . base64_encode($user['password']);
+ if ($user['ip']) {
+ $usr .= ":{$user['ip']}";
+ }
+ $username[] = $usr;
+ }
+ $config['pppoes']['pppoe'][0]['username'] = implode(" ", $username);
+ }
+ unset($config['pppoe']);
+ }
+}
+
+function upgrade_068_to_069() {
+ global $config;
+ if (!is_array($config['system']['user'])) {
+ return;
+ }
+ foreach ($config['system']['user'] as & $user) {
+ if (!is_array($user['cert'])) {
+ continue;
+ }
+ $rids = array();
+ foreach ($user['cert'] as $id => $cert) {
+ if (!isset($cert['descr'])) {
+ continue;
+ }
+ $tcert = $cert;
+ // Make sure each cert gets a refid
+ if (!isset($tcert['refid'])) {
+ $tcert['refid'] = uniqid();
+ }
+ // Keep the cert references for this user
+ $rids[] = $tcert['refid'];
+ $config['cert'][] = $tcert;
+ }
+ // Replace user certs with cert references instead.
+ if (count($rids) > 0) {
+ $user['cert'] = $rids;
+ }
+ }
+}
+
+function upgrade_069_to_070() {
+ global $config;
+
+ /* Convert NAT 1:1 rules */
+ if (is_array($config['nat']['onetoone'])) {
+ foreach ($config['nat']['onetoone'] as $nidx => $natent) {
+ if ($natent['subnet'] == 32) {
+ $config['nat']['onetoone'][$nidx]['source'] = array("address" => $natent['internal']);
+ } else {
+ $config['nat']['onetoone'][$nidx]['source'] = array("address" => $natent['internal'] . "/" . $natent['subnet']);
+ }
+
+ $config['nat']['onetoone'][$nidx]['destination'] = array("any" => true);
+
+ unset($config['nat']['onetoone'][$nidx]['internal']);
+ unset($config['nat']['onetoone'][$nidx]['subnet']);
+ }
+
+ unset($natent);
+ }
+}
+
+function upgrade_070_to_071() {
+ global $config;
+
+ if (is_array($config['cron']['item'])) {
+ foreach ($config['cron']['item'] as $idx => $cronitem) {
+ if (stristr($cronitem['command'], "checkreload.sh")) {
+ unset($config['cron']['item'][$idx]);
+ break;
+ }
+ }
+ }
+}
+
+function rename_field(& $section, $oldname, $newname) {
+ if (is_array($section)) {
+ foreach ($section as & $item) {
+ if (is_array($item) && !empty($item[$oldname])) {
+ $item[$newname] = $item[$oldname];
+ }
+ if (is_array($item) && isset($item[$oldname])) {
+ unset($item[$oldname]);
+ }
+ }
+ }
+}
+
+function upgrade_071_to_072() {
+ global $config;
+ if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
+ rename_field($config['sysctl']['item'], 'desc', 'descr');
+ }
+}
+
+function upgrade_072_to_073() {
+ global $config;
+ if (!is_array($config['load_balancer'])) {
+ return;
+ }
+ if (is_array($config['load_balancer']['monitor_type'])) {
+ rename_field($config['load_balancer']['monitor_type'], 'desc', 'descr');
+ }
+ if (is_array($config['load_balancer']['lbpool'])) {
+ rename_field($config['load_balancer']['lbpool'], 'desc', 'descr');
+ }
+ if (is_array($config['load_balancer']['lbaction'])) {
+ rename_field($config['load_balancer']['lbaction'], 'desc', 'descr');
+ }
+ if (is_array($config['load_balancer']['lbprotocol'])) {
+ rename_field($config['load_balancer']['lbprotocol'], 'desc', 'descr');
+ }
+ if (is_array($config['load_balancer']['virtual_server'])) {
+ rename_field($config['load_balancer']['virtual_server'], 'desc', 'descr');
+ }
+}
+
+function upgrade_073_to_074() {
+ global $config;
+ rename_field($config['system']['user'], 'fullname', 'descr');
+}
+
+function upgrade_074_to_075() {
+ global $config;
+ if (is_array($config['ca'])) {
+ rename_field($config['ca'], 'name', 'descr');
+ }
+ if (is_array($config['cert'])) {
+ rename_field($config['cert'], 'name', 'descr');
+ }
+ if (is_array($config['crl'])) {
+ rename_field($config['crl'], 'name', 'descr');
+ }
+}
+
+function upgrade_075_to_076() {
+ global $config;
+ $cron_item = array();
+ $cron_item['minute'] = "30";
+ $cron_item['hour'] = "12";
+ $cron_item['mday'] = "*";
+ $cron_item['month'] = "*";
+ $cron_item['wday'] = "*";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.update_urltables";
+ $config['cron']['item'][] = $cron_item;
+}
+
+function upgrade_076_to_077() {
+ global $config;
+ foreach ($config['filter']['rule'] as & $rule) {
+ if (isset($rule['protocol']) && !empty($rule['protocol'])) {
+ $rule['protocol'] = strtolower($rule['protocol']);
+ }
+ }
+}
+
+function upgrade_077_to_078() {
+ global $config;
+ if (is_array($config['pptpd']) && is_array($config['pptpd']['radius']) &&
+ !is_array($config['pptpd']['radius']['server'])) {
+ $radarr = array();
+ $radsvr = array();
+ $radsvr['ip'] = $config['pptpd']['radius']['server'];
+ $radsvr['secret'] = $config['pptpd']['radius']['secret'];
+ $radsvr['port'] = 1812;
+ $radsvr['acctport'] = 1813;
+ $radsvr['enable'] = isset($config['pptpd']['radius']['enable']);
+ $radarr['accounting'] = isset($config['pptpd']['radius']['accounting']);
+ if ($radarr['accounting']) {
+ $radarr['acct_update'] = $radsvr['ip'];
+ }
+ $radarr['server'] = $radsvr;
+ $config['pptpd']['radius'] = $radarr;
+ }
+ if (is_array($config['pptpd'])) {
+ $config['pptpd']['n_pptp_units'] = empty($config['pptpd']['n_pptp_units']) ? 16 : $config['pptpd']['n_pptp_units'];
+ }
+}
+function upgrade_078_to_079() {
+ global $g;
+ /* Delete old and unused RRD file */
+ unlink_if_exists("{$g['vardb_path']}/rrd/captiveportal-totalusers.rrd");
+}
+
+function upgrade_079_to_080() {
+ global $config;
+
+ /* Upgrade config in 1.2.3 specifying a username other than admin for syncing. */
+ if (!empty($config['system']['username']) && is_array($config['installedpackages']['carpsettings']) &&
+ is_array($config['installedpackages']['carpsettings']['config'])) {
+ $config['installedpackages']['carpsettings']['config'][0]['username'] = $config['system']['username'];
+ unset($config['system']['username']);
+ }
+}
+
+function upgrade_080_to_081() {
+ global $config;
+ global $g;
+ /* Welcome to the 2.1 migration path */
+
+ /* tag all the existing gateways as being IPv4 */
+ $i = 0;
+ if (is_array($config['gateways']['gateway_item'])) {
+ foreach ($config['gateways']['gateway_item'] as $gw) {
+ $config['gateways']['gateway_item'][$i]['ipprotocol'] = "inet";
+ $i++;
+ }
+ }
+
+ /* RRD files changed for quality, traffic and packets graphs */
+ /* convert traffic RRD file */
+ global $parsedcfg, $listtags;
+ $listtags = array("ds", "v", "rra", "row");
+
+ $rrddbpath = "/var/db/rrd/";
+ $rrdtool = "/usr/bin/nice -n20 /usr/local/bin/rrdtool";
+
+ if ($g['platform'] != "pfSense") {
+ /* restore the databases, if we have one */
+ if (restore_rrd()) {
+ /* Make sure to move the rrd backup out of the way. We will make a new one after converting. */
+ @rename("{$g['cf_conf_path']}/rrd.tgz", "{$g['cf_conf_path']}/backup/rrd.tgz");
+ }
+ }
+
+ $rrdinterval = 60;
+ $valid = $rrdinterval * 2;
+
+ /* Asume GigE for now */
+ $downstream = 125000000;
+ $upstream = 125000000;
+
+ /* build a list of traffic and packets databases */
+ $databases = return_dir_as_array($rrddbpath, '/-(traffic|packets)\.rrd$/');
+ rsort($databases);
+ foreach ($databases as $database) {
+ $xmldump = "{$database}.old.xml";
+ $xmldumpnew = "{$database}.new.xml";
+
+ if (platform_booting()) {
+ echo "Migrate RRD database {$database} to new format for IPv6.\n";
+ }
+
+ /* dump contents to xml and move database out of the way */
+ dump_rrd_to_xml("{$rrddbpath}/{$database}", "{$g['tmp_path']}/{$xmldump}");
+
+ /* search and replace tags to add data sources */
+ $ds_search = "<!-- Round Robin Archives -->";
+ $ds_arr = array();
+ $ds_arr[] = " <ds>
+ <name> inpass6 </name>
+ <type> COUNTER </type>
+ <minimal_heartbeat> {$valid} </minimal_heartbeat>
+ <min> 0.0000000000e+00 </min>
+ <max> 1.2500000000e+08 </max>
+
+ <!-- PDP Status -->
+ <last_ds> 0 </last_ds>
+ <value> NaN </value>
+ <unknown_sec> 3 </unknown_sec>
+ </ds>
+ ";
+ $ds_arr[] = " <ds>
+ <name> outpass6 </name>
+ <type> COUNTER </type>
+ <minimal_heartbeat> {$valid} </minimal_heartbeat>
+ <min> 0.0000000000e+00 </min>
+ <max> 1.2500000000e+08 </max>
+
+ <!-- PDP Status -->
+ <last_ds> 0 </last_ds>
+ <value> NaN </value>
+ <unknown_sec> 3 </unknown_sec>
+ </ds>
+ ";
+ $ds_arr[] = " <ds>
+ <name> inblock6 </name>
+ <type> COUNTER </type>
+ <minimal_heartbeat> {$valid} </minimal_heartbeat>
+ <min> 0.0000000000e+00 </min>
+ <max> 1.2500000000e+08 </max>
+
+ <!-- PDP Status -->
+ <last_ds> 0 </last_ds>
+ <value> NaN </value>
+ <unknown_sec> 3 </unknown_sec>
+ </ds>
+ ";
+ $ds_arr[] = " <ds>
+ <name> outblock6 </name>
+ <type> COUNTER </type>
+ <minimal_heartbeat> {$valid} </minimal_heartbeat>
+ <min> 0.0000000000e+00 </min>
+ <max> 1.2500000000e+08 </max>
+
+ <!-- PDP Status -->
+ <last_ds> 0 </last_ds>
+ <value> NaN </value>
+ <unknown_sec> 3 </unknown_sec>
+ </ds>
+ ";
+
+ $cdp_search = "<\/cdp_prep>";
+ $cdp_replace = "</cdp_prep>";
+ $cdp_arr = array();
+ $cdp_arr[] = " <ds>
+ <primary_value> NaN </primary_value>
+ <secondary_value> 0.0000000000e+00 </secondary_value>
+ <value> NaN </value>
+ <unknown_datapoints> 0 </unknown_datapoints>
+ </ds>
+ ";
+ $cdp_arr[] = " <ds>
+ <primary_value> NaN </primary_value>
+ <secondary_value> 0.0000000000e+00 </secondary_value>
+ <value> NaN </value>
+ <unknown_datapoints> 0 </unknown_datapoints>
+ </ds>
+ ";
+ $cdp_arr[] = " <ds>
+ <primary_value> NaN </primary_value>
+ <secondary_value> 0.0000000000e+00 </secondary_value>
+ <value> NaN </value>
+ <unknown_datapoints> 0 </unknown_datapoints>
+ </ds>
+ ";
+ $cdp_arr[] = " <ds>
+ <primary_value> NaN </primary_value>
+ <secondary_value> 0.0000000000e+00 </secondary_value>
+ <value> NaN </value>
+ <unknown_datapoints> 0 </unknown_datapoints>
+ </ds>
+ ";
+
+ $value_search = "<\/row>";
+ $value_replace = "</row>";
+ $value = "<v> NaN </v>";
+
+ $xml = file_get_contents("{$g['tmp_path']}/{$xmldump}");
+ foreach ($ds_arr as $ds) {
+ $xml = preg_replace("/$ds_search/s", "$ds{$ds_search}", $xml);
+ }
+ foreach ($cdp_arr as $cdp) {
+ $xml = preg_replace("/$cdp_search/s", "$cdp{$cdp_replace}", $xml);
+ }
+ foreach ($ds_arr as $ds) {
+ $xml = preg_replace("/$value_search/s", "$value{$value_replace}", $xml);
+ }
+
+ file_put_contents("{$g['tmp_path']}/{$xmldumpnew}", $xml);
+ mwexec("$rrdtool restore -f {$g['tmp_path']}/{$xmldumpnew} {$rrddbpath}/{$database} 2>&1");
+ unset($xml);
+ # Default /tmp tmpfs is ~40mb, do not leave temp files around
+ unlink_if_exists("{$g['tmp_path']}/{$xmldump}");
+ unlink_if_exists("{$g['tmp_path']}/{$xmldumpnew}");
+ }
+ if (!platform_booting()) {
+ enable_rrd_graphing();
+ }
+ /* Let's save the RRD graphs after we run enable RRD graphing */
+ /* The function will restore the rrd.tgz so we will save it after */
+ exec("cd /; LANG=C NO_REMOUNT=1 RRDDBPATH='{$rrddbpath}' CF_CONF_PATH='{$g['cf_conf_path']}' /etc/rc.backup_rrd.sh");
+ if (platform_booting()) {
+ echo "Updating configuration...";
+ }
+ foreach ($config['filter']['rule'] as & $rule) {
+ if (isset($rule['protocol']) && !empty($rule['protocol'])) {
+ $rule['protocol'] = strtolower($rule['protocol']);
+ }
+ }
+ unset($rule);
+}
+
+function upgrade_081_to_082() {
+ /* don't enable the allow IPv6 toggle */
+}
+
+function upgrade_082_to_083() {
+ global $config;
+
+ /* Upgrade captiveportal config */
+ if (!empty($config['captiveportal'])) {
+ $tmpcp = $config['captiveportal'];
+ $config['captiveportal'] = array();
+ $config['captiveportal']['cpzone'] = array();
+ $config['captiveportal']['cpzone'] = $tmpcp;
+ $config['captiveportal']['cpzone']['zoneid'] = 8000;
+ $config['captiveportal']['cpzone']['zone'] = "cpzone";
+ if ($config['captiveportal']['cpzone']['auth_method'] == "radius") {
+ $config['captiveportal']['cpzone']['radius_protocol'] = "PAP";
+ }
+ }
+ if (!empty($config['voucher'])) {
+ $tmpcp = $config['voucher'];
+ $config['voucher'] = array();
+ $config['voucher']['cpzone'] = array();
+ $config['voucher']['cpzone'] = $tmpcp;
+ }
+}
+
+function upgrade_083_to_084() {
+ global $config;
+ if (!isset($config['hasync'])) {
+ if (!empty($config['installedpackages']) &&
+ !empty($config['installedpackages']['carpsettings']) &&
+ !empty($config['installedpackages']['carpsettings']['config'])) {
+ $config['hasync'] = $config['installedpackages']['carpsettings']['config'][0];
+ unset($config['installedpackages']['carpsettings']);
+ }
+ if (empty($config['installedpackages']['carpsettings'])) {
+ unset($config['installedpackages']['carpsettings']);
+ }
+ if (empty($config['installedpackages'])) {
+ unset($config['installedpackages']);
+ }
+ }
+}
+
+function upgrade_084_to_085() {
+ global $config;
+
+ $gateway_group_arr = array();
+ $gateways = return_gateways_array();
+ $oldnames = array();
+ /* setup translation array */
+ foreach ($gateways as $name => $gw) {
+ if (isset($gw['dynamic'])) {
+ $oldname = strtoupper($config['interfaces'][$gw['friendlyiface']]['descr']);
+ $oldnames[$oldname] = $name;
+ } else {
+ $oldnames[$name] = $name;
+ }
+ }
+
+ /* process the old array */
+ if (is_array($config['gateways']['gateway_group'])) {
+ $group_array_new = array();
+ foreach ($config['gateways']['gateway_group'] as $name => $group) {
+ if (is_array($group['item'])) {
+ $newlist = array();
+ foreach ($group['item'] as $entry) {
+ $elements = explode("|", $entry);
+ if ($oldnames[$elements[0]] <> "") {
+ $newlist[] = "{$oldnames[$elements[0]]}|{$elements[1]}";
+ } else {
+ $newlist[] = "{$elements[0]}|{$elements[1]}";
+ }
+ }
+ $group['item'] = $newlist;
+ $group_array_new[$name] = $group;
+ }
+ }
+ $config['gateways']['gateway_group'] = $group_array_new;
+ }
+ /* rename old Quality RRD files in the process */
+ $rrddbpath = "/var/db/rrd";
+ foreach ($oldnames as $old => $new) {
+ if (is_readable("{$rrddbpath}/{$old}-quality.rrd")) {
+ @rename("{$rrddbpath}/{$old}-quality.rrd", "{$rrddbpath}/{$new}-quality.rrd");
+ }
+ }
+ unset($gateways, $oldnames, $gateway_group_arr);
+}
+
+function upgrade_085_to_086() {
+ global $config, $g;
+
+ /* XXX: Gross hacks in sight */
+ if (is_array($config['virtualip']['vip'])) {
+ $vipchg = array();
+ foreach ($config['virtualip']['vip'] as $vip) {
+ if ($vip['mode'] != "carp") {
+ continue;
+ }
+ $config = array_replace_values_recursive(
+ $config,
+ '^vip' . $vip['vhid'] . '$',
+ "{$vip['interface']}_vip{$vip['vhid']}"
+ );
+ }
+ }
+}
+
+function upgrade_086_to_087() {
+ global $config, $dummynet_pipe_list;
+
+ if (!is_array($config['dnshaper']) || !is_array($config['dnshaper']['queue'])) {
+ return;
+ }
+
+ $dnqueue_number = 1;
+ $dnpipe_number = 1;
+
+ foreach ($config['dnshaper']['queue'] as $idx => $dnpipe) {
+ $config['dnshaper']['queue'][$idx]['number'] = $dnpipe_number;
+ $dnpipe_number++;
+ if (is_array($dnpipe['queue'])) {
+ foreach ($dnpipe['queue'] as $qidx => $dnqueue) {
+ $config['dnshaper']['queue'][$idx]['queue'][$qidx]['number'] = $dnqueue_number;
+ $dnqueue_number++;
+ }
+ }
+ }
+
+ unset($dnqueue_number, $dnpipe_number, $qidx, $idx, $dnpipe, $dnqueue);
+
+ if (!is_array($config['filter']) || !is_array($config['filter']['rule'])) {
+ return;
+ }
+
+ require_once("shaper.inc");
+ read_dummynet_config();
+
+ $dn_list = array();
+ if (is_array($dummynet_pipe_list)) {
+ foreach ($dummynet_pipe_list as $dn) {
+ $tmplist =& $dn->get_queue_list();
+ foreach ($tmplist as $qname => $link) {
+ $dn_list[$link] = $qname;
+ }
+ }
+ unset($dummynet_pipe_list);
+ }
+
+ foreach ($config['filter']['rule'] as $idx => $rule) {
+ if (!empty($rule['dnpipe'])) {
+ if (!empty($dn_list[$rule['dnpipe']])) {
+ $config['filter']['rule'][$idx]['dnpipe'] = $dn_list[$rule['dnpipe']];
+ }
+ }
+ if (!empty($rule['pdnpipe'])) {
+ if (!empty($dn_list[$rule['pdnpipe']])) {
+ $config['filter']['rule'][$idx]['pdnpipe'] = $dn_list[$rule['pdnpipe']];
+ }
+ }
+ }
+}
+function upgrade_087_to_088() {
+ global $config;
+ if (isset($config['system']['glxsb_enable'])) {
+ unset($config['system']['glxsb_enable']);
+ $config['system']['crypto_hardware'] = "glxsb";
+ }
+}
+
+function upgrade_088_to_089() {
+ global $config;
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+
+ /* migrate captive portal ssl to certificate manager */
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $id => &$setting) {
+ if (isset($setting['httpslogin'])) {
+ /* create cert entry */
+ $cert = array();
+ $cert['refid'] = uniqid();
+ $cert['descr'] = "Captive Portal Cert - {$setting['zone']}";
+ $cert['crt'] = $setting['certificate'];
+ $cert['prv'] = $setting['private-key'];
+
+ if (!empty($setting['cacertificate'])) {
+ /* create ca entry */
+ $ca = array();
+ $ca['refid'] = uniqid();
+ $ca['descr'] = "Captive Portal CA - {$setting['zone']}";
+ $ca['crt'] = $setting['cacertificate'];
+ $config['ca'][] = $ca;
+
+ /* add ca reference to certificate */
+ $cert['caref'] = $ca['refid'];
+ }
+
+ $config['cert'][] = $cert;
+
+ /* create cert reference */
+ $setting['certref'] = $cert['refid'];
+
+ unset($setting['certificate']);
+ unset($setting['private-key']);
+ unset($setting['cacertificate']);
+
+ }
+ }
+ }
+}
+
+function upgrade_089_to_090() {
+ global $config;
+ if (is_array($config['load_balancer']['virtual_server']) && count($config['load_balancer']['virtual_server'])) {
+ $vs_a = &$config['load_balancer']['virtual_server'];
+ for ($i = 0; isset($vs_a[$i]); $i++) {
+ if (is_array($vs_a[$i]['pool'])) {
+ $vs_a[$i]['poolname'] = $vs_a[$i]['pool'][0];
+ unset($vs_a[$i]['pool']);
+ } elseif (!empty($vs_a[$i]['pool'])) {
+ $vs_a[$i]['poolname'] = $vs_a[$i]['pool'];
+ unset($vs_a[$i]['pool']);
+ }
+ }
+ }
+}
+
+function upgrade_090_to_091() {
+ global $config;
+
+ if (is_array($config['dnshaper']) && is_array($config['dnshaper']['queue'])) {
+ foreach ($config['dnshaper']['queue'] as $idx => $dnqueue) {
+ if (!empty($dnqueue['bandwidth'])) {
+ $bw = array();
+ $bw['bw'] = $dnqueue['bandwidth'];
+ $bw['bwscale'] = $dnqueue['bandwidthtype'];
+ $bw['bwsched'] = "none";
+ $config['dnshaper']['queue'][$idx]['bandwidth'] = array();
+ $config['dnshaper']['queue'][$idx]['bandwidth']['item'] = array();
+ $config['dnshaper']['queue'][$idx]['bandwidth']['item'][] = $bw;
+ }
+ }
+ }
+}
+
+function upgrade_091_to_092() {
+ global $config;
+
+ if (is_array($config['nat']['advancedoutbound']) && is_array($config['nat']['advancedoutbound']['rule'])) {
+ $nat_rules = &$config['nat']['advancedoutbound']['rule'];
+ for ($i = 0; isset($nat_rules[$i]); $i++) {
+ if (empty($nat_rules[$i]['interface'])) {
+ $nat_rules[$i]['interface'] = 'wan';
+ }
+ }
+ }
+}
+
+function upgrade_092_to_093() {
+ global $g;
+
+ $suffixes = array("concurrent", "loggedin");
+
+ foreach ($suffixes as $suffix) {
+ if (file_exists("{$g['vardb_path']}/rrd/captiveportal-{$suffix}.rrd")) {
+ rename("{$g['vardb_path']}/rrd/captiveportal-{$suffix}.rrd",
+ "{$g['vardb_path']}/rrd/captiveportal-cpZone-{$suffix}.rrd");
+ }
+ }
+
+ if (!platform_booting()) {
+ enable_rrd_graphing();
+ }
+}
+
+function upgrade_093_to_094() {
+ global $config;
+
+ if (isset($config['system']['powerd_mode'])) {
+ $config['system']['powerd_ac_mode'] = $config['system']['powerd_mode'];
+ $config['system']['powerd_battery_mode'] = $config['system']['powerd_mode'];
+ unset($config['system']['powerd_mode']);
+ }
+}
+
+function upgrade_094_to_095() {
+ global $config;
+
+ if (!isset($config['interfaces']) || !is_array($config['interfaces'])) {
+ return;
+ }
+
+ foreach ($config['interfaces'] as $iface => $cfg) {
+ if (isset($cfg['ipaddrv6']) && ($cfg['ipaddrv6'] == "track6")) {
+ if (!isset($cfg['track6-prefix-id']) || ($cfg['track6-prefix-id'] == "")) {
+ $config['interfaces'][$iface]['track6-prefix-id'] = 0;
+ }
+ }
+ }
+}
+
+function upgrade_095_to_096() {
+ global $config, $g;
+
+ $names = array("inpass", "outpass", "inblock", "outblock",
+ "inpass6", "outpass6", "inblock6", "outblock6");
+ $rrddbpath = "/var/db/rrd";
+ $rrdtool = "/usr/local/bin/rrdtool";
+
+ if ($g['platform'] != "pfSense") {
+ /* restore the databases, if we have one */
+ if (restore_rrd()) {
+ /* Make sure to move the rrd backup out of the way. We will make a new one after converting. */
+ @rename("{$g['cf_conf_path']}/rrd.tgz", "{$g['cf_conf_path']}/backup/rrd.tgz");
+ }
+ }
+
+ /* Assume 2*10GigE for now */
+ $stream = 2500000000;
+
+ /* build a list of traffic and packets databases */
+ $databases = return_dir_as_array($rrddbpath, '/-(traffic|packets)\.rrd$/');
+ rsort($databases);
+ foreach ($databases as $database) {
+ if (platform_booting()) {
+ echo "Update RRD database {$database}.\n";
+ }
+
+ $cmd = "{$rrdtool} tune {$rrddbpath}/{$database}";
+ foreach ($names as $name) {
+ $cmd .= " -a {$name}:{$stream}";
+ }
+ mwexec("{$cmd} 2>&1");
+
+ }
+ if (!platform_booting()) {
+ enable_rrd_graphing();
+ }
+ /* Let's save the RRD graphs after we run enable RRD graphing */
+ /* The function will restore the rrd.tgz so we will save it after */
+ exec("cd /; LANG=C NO_REMOUNT=1 RRDDBPATH='{$rrddbpath}' CF_CONF_PATH='{$g['cf_conf_path']}' /etc/rc.backup_rrd.sh");
+}
+
+function upgrade_096_to_097() {
+ global $config, $g;
+ /* If the user had disabled default block rule logging before, then bogon/private network logging was already off, so respect their choice. */
+ if (isset($config['syslog']['nologdefaultblock'])) {
+ $config['syslog']['nologbogons'] = true;
+ $config['syslog']['nologprivatenets'] = true;
+ }
+}
+
+function upgrade_097_to_098() {
+ global $config, $g;
+ /* Disable kill_states by default */
+ $config['system']['kill_states'] = true;
+}
+
+function upgrade_098_to_099() {
+ global $config;
+
+ if (empty($config['dhcpd']) || !is_array($config['dhcpd'])) {
+ return;
+ }
+
+ foreach ($config['dhcpd'] as & $dhcpifconf) {
+ if (isset($dhcpifconf['next-server'])) {
+ $dhcpifconf['nextserver'] = $dhcpifconf['next-server'];
+ unset($dhcpifconf['next-server']);
+ }
+ }
+}
+
+function upgrade_099_to_100() {
+ require_once("/etc/inc/services.inc");
+ install_cron_job("/usr/bin/nice -n20 newsyslog", false);
+}
+
+function upgrade_100_to_101() {
+ global $config, $g;
+
+ if (!is_array($config['voucher'])) {
+ return;
+ }
+
+ foreach ($config['voucher'] as $cpzone => $cp) {
+ if (!is_array($cp['roll'])) {
+ continue;
+ }
+ foreach ($cp['roll'] as $ridx => $rcfg) {
+ if (!empty($rcfg['comment'])) {
+ $config['voucher'][$cpzone]['roll'][$ridx]['descr'] = $rcfg['comment'];
+ }
+ }
+ }
+}
+
+function upgrade_101_to_102() {
+ global $config, $g;
+
+ if (is_array($config['captiveportal'])) {
+ foreach ($config['captiveportal'] as $cpzone => $cp) {
+ if (!is_array($cp['passthrumac'])) {
+ continue;
+ }
+
+ foreach ($cp['passthrumac'] as $idx => $passthrumac) {
+ $config['captiveportal'][$cpzone]['passthrumac'][$idx]['action'] = 'pass';
+ }
+ }
+ }
+
+ /* Convert OpenVPN Compression option to the new style */
+ // Nothing to do if there is no OpenVPN tag
+ if (isset($config['openvpn']) && is_array($config['openvpn'])) {
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as &$vpn) {
+ if (!empty($vpn['compression'])) {
+ $vpn['compression'] = "adaptive";
+ }
+ }
+ }
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as &$vpn) {
+ if (!empty($vpn['compression'])) {
+ $vpn['compression'] = "adaptive";
+ }
+ }
+ }
+ }
+}
+
+function upgrade_102_to_103() {
+ global $config;
+
+ if (isset($config['nat']['advancedoutbound']['enable'])) {
+ $config['nat']['advancedoutbound']['mode'] = "advanced";
+ unset($config['nat']['advancedoutbound']['enable']);
+ } else {
+ $config['nat']['advancedoutbound']['mode'] = "automatic";
+ }
+
+ $config['nat']['outbound'] = $config['nat']['advancedoutbound'];
+
+ unset($config['nat']['ipsecpassthru']);
+ unset($config['nat']['advancedoutbound']);
+}
+
+function upgrade_103_to_104() {
+ global $config;
+
+ $changed_privs = array(
+ "page-diag-system-activity" => "page-diagnostics-system-activity",
+ "page-interfacess-groups" => "page-interfaces-groups",
+ "page-interfacess-lagg" => "page-interfaces-lagg",
+ "page-interfacess-qinq" => "page-interfaces-qinq"
+ );
+
+ /* update user privileges */
+ foreach ($config['system']['user'] as & $user) {
+ if (!is_array($user['priv'])) {
+ continue;
+ }
+ foreach ($user['priv'] as & $priv) {
+ if (array_key_exists($priv, $changed_privs)) {
+ $priv = $changed_privs[$priv];
+ }
+ }
+ }
+
+ /* update group privileges */
+ foreach ($config['system']['group'] as & $group) {
+ if (!is_array($group['priv'])) {
+ continue;
+ }
+ foreach ($group['priv'] as & $priv) {
+ if (array_key_exists($priv, $changed_privs)) {
+ $priv = $changed_privs[$priv];
+ }
+ }
+ }
+
+ /* sync all local account information */
+ local_sync_accounts();
+}
+
+function upgrade_104_to_105() {
+ global $config;
+
+ if (is_array($config['captiveportal'])) {
+ $zoneid = 2;
+ foreach ($config['captiveportal'] as $cpzone => $cpcfg) {
+ if (empty($cpcfg['zoneid'])) {
+ $config['captiveportal'][$cpzone]['zoneid'] = $zoneid;
+ $zoneid += 2;
+ } else if ($cpcfg['zoneid'] > 4000) {
+ $config['captiveportal'][$cpzone]['zoneid'] = $zoneid;
+ $zoneid += 2;
+ }
+ }
+ }
+}
+
+function upgrade_105_to_106() {
+
+ /* NOTE: This entry can be reused for something else since the upgrade code was reverted */
+}
+
+function upgrade_106_to_107() {
+ global $config;
+
+ if (is_array($config['filter']) && is_array($config['filter']['rule'])) {
+ $tracker = (int)microtime(true);
+ foreach ($config['filter']['rule'] as $ridx => $rule) {
+ if (empty($rule['tracker'])) {
+ $config['filter']['rule'][$ridx]['tracker'] = $tracker;
+ $tracker++;
+ }
+ }
+ unset($tracker, $ridx);
+ }
+ if (is_array($config['nat']) && is_array($config['nat']['rule'])) {
+ $tracker = (int)microtime(true);
+ foreach ($config['nat']['rule'] as $ridx => $rule) {
+ if (empty($rule['tracker'])) {
+ $config['nat']['rule'][$ridx]['tracker'] = $tracker;
+ $tracker++;
+ }
+ }
+ unset($tracker, $ridx);
+ }
+}
+
+function upgrade_107_to_108() {
+ global $config;
+
+ if (isset($config['system']['webgui']['noautocomplete'])) {
+ unset($config['system']['webgui']['noautocomplete']);
+ } else {
+ $config['system']['webgui']['loginautocomplete'] = true;
+ }
+}
+
+function upgrade_108_to_109() {
+ global $config;
+
+ if (!isset($config['filter']['rule']) || !is_array($config['filter']['rule'])) {
+ return;
+ }
+
+ foreach ($config['filter']['rule'] as &$rule) {
+ if (!isset($rule['dscp']) || empty($rule['dscp'])) {
+ continue;
+ }
+
+ $pos = strpos($rule['dscp'], ' ');
+ if ($pos !== false) {
+ $rule['dscp'] = substr($rule['dscp'], 0, $pos);
+ }
+ unset($pos);
+ }
+}
+
+function upgrade_109_to_110() {
+ global $config;
+
+ if (!is_array($config['ipsec']) || !is_array($config['ipsec']['phase2'])) {
+ return;
+ }
+
+ foreach ($config['ipsec']['phase2'] as &$rule) {
+ if (!empty($rule['uniqid'])) {
+ continue;
+ }
+
+ $rule['uniqid'] = uniqid();
+ }
+}
+
+function upgrade_110_to_111() {
+ global $config;
+
+ /* Make sure unbound user exist */
+ mwexec('/usr/sbin/pw groupadd -n unbound -g 59', true);
+ mwexec('/usr/sbin/pw useradd -n unbound -c "Unbound DNS Resolver" -d /var/unbound -s /usr/sbin/nologin -u 59 -g 59', true);
+
+ /* cleanup old unbound package stuffs */
+ unlink_if_exists("/usr/local/pkg/unbound.xml");
+ unlink_if_exists("/usr/local/pkg/unbound.inc");
+ unlink_if_exists("/usr/local/pkg/unbound_advanced.xml");
+ unlink_if_exists("/usr/local/www/unbound_status.php");
+ unlink_if_exists("/usr/local/www/unbound_acls.php");
+ unlink_if_exists("/usr/local/bin/unbound_monitor.sh");
+ unlink_if_exists("/usr/local/etc/rc.d/unbound.sh");
+
+ /* Remove old menu and service entries */
+ if (isset($config['installedpackages']['menu']) && is_array($config['installedpackages']['menu'])) {
+ foreach ($config['installedpackages']['menu'] as $idx => $menu) {
+ if ($menu['name'] != 'Unbound DNS') {
+ continue;
+ }
+
+ unset($config['installedpackages']['menu'][$idx]);
+ break;
+ }
+ }
+
+ if (isset($config['installedpackages']['service']) && is_array($config['installedpackages']['service'])) {
+ foreach ($config['installedpackages']['service'] as $idx => $service) {
+ if ($service['name'] != 'unbound') {
+ continue;
+ }
+ unset($config['installedpackages']['service'][$idx]);
+ break;
+ }
+ }
+
+ if (!isset($config['installedpackages']['unbound']['config'][0])) {
+ return;
+ }
+
+ $pkg = $config['installedpackages']['unbound']['config'][0];
+
+ if (isset($config['installedpackages']['unboundadvanced']['config'][0])) {
+ $pkg = array_merge($pkg, $config['installedpackages']['unboundadvanced']['config'][0]);
+ }
+
+ $new = array();
+
+ /* deal first with boolean fields */
+ $fields = array(
+ "enable" => "enable",
+ "dnssec_status" => "dnssec",
+ "forwarding_mode" => "forwarding",
+ "regdhcp" => "regdhcp",
+ "regdhcpstatic" => "regdhcpstatic",
+ "txtsupport" => "txtsupport",
+ "hide_id" => "hideidentity",
+ "hide_version" => "hideversion",
+ "prefetch" => "prefetch",
+ "prefetch_key" => "prefetchkey",
+ "harden_glue" => "hardenglue",
+ "harden_dnssec_stripped" => "dnssec_stripped");
+
+ foreach ($fields as $oldk => $newk) {
+ if (isset($pkg[$oldk])) {
+ if ($pkg[$oldk] == 'on') {
+ $new[$newk] = true;
+ }
+ unset($pkg[$oldk]);
+ }
+ }
+
+ $fields = array(
+ "active_interface" => "network_interface",
+ "query_interface" => "outgoing_interface",
+ "unbound_verbosity" => "log_verbosity",
+ "unbound_verbosity" => "log_verbosity",
+ "msg_cache_size" => "msgcachesize",
+ "outgoing_num_tcp" => "outgoing_num_tcp",
+ "incoming_num_tcp" => "incoming_num_tcp",
+ "edns_buffer_size" => "edns_buffer_size",
+ "num_queries_per_thread" => "num_queries_per_thread",
+ "jostle_timeout" => "jostle_timeout",
+ "cache_max_ttl" => "cache_max_ttl",
+ "cache_min_ttl" => "cache_min_ttl",
+ "infra_host_ttl" => "infra_host_ttl",
+ "infra_cache_numhosts" => "infra_cache_numhosts",
+ "unwanted_reply_threshold" => "unwanted_reply_threshold",
+ "custom_options" => "custom_options");
+
+ foreach ($fields as $oldk => $newk) {
+ if (isset($pkg[$oldk])) {
+ $new[$newk] = $pkg[$oldk];
+ unset($pkg[$oldk]);
+ }
+ }
+
+ if (isset($new['custom_options']) && !empty($new['custom_options'])) {
+ $new['custom_options'] = str_replace("\r\n", "\n", $new['custom_options']);
+ }
+
+ /* Following options were removed, bring them as custom_options */
+ if (isset($pkg['stats']) && $pkg['stats'] == "on") {
+ if (isset($pkg['stats_interval'])) {
+ $new['custom_options'] .= (empty($new['custom_options']) ? "" : "\n") . "statistics-interval: {$pkg['stats_interval']}";
+ }
+ if (isset($pkg['cumulative_stats'])) {
+ $new['custom_options'] .= (empty($new['custom_options']) ? "" : "\n") . "statistics-cumulative: {$pkg['cumulative_stats']}";
+ }
+ if (isset($pkg['extended_stats']) && $pkg['extended_stats'] == "on") {
+ $new['custom_options'] .= (empty($new['custom_options']) ? "" : "\n") . "extended-statistics: yes";
+ } else {
+ $new['custom_options'] .= (empty($new['custom_options']) ? "" : "\n") . "extended-statistics: no";
+ }
+ }
+
+ $new['acls'] = array();
+ if (isset($config['installedpackages']['unboundacls']['config']) &&
+ is_array($config['installedpackages']['unboundacls']['config'])) {
+ foreach ($config['installedpackages']['unboundacls']['config'] as $acl) {
+ $new['acls'][] = $acl;
+ }
+ }
+
+ $config['unbound'] = $new;
+
+ if (isset($config['installedpackages']['unbound'])) {
+ unset($config['installedpackages']['unbound']);
+ }
+ if (isset($config['installedpackages']['unboundadvanced'])) {
+ unset($config['installedpackages']['unboundadvanced']);
+ }
+ if (isset($config['installedpackages']['unboundacls'])) {
+ unset($config['installedpackages']['unboundacls']);
+ }
+
+ unset($pkg, $new);
+}
+
+function upgrade_111_to_112() {
+ global $config;
+
+ $config['cron']['item'][] = array(
+ 'minute' => '*/60',
+ 'hour' => '*',
+ 'mday' => '*',
+ 'month' => '*',
+ 'wday' => '*',
+ 'who' => 'root',
+ 'command' => '/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 webConfiguratorlockout'
+ );
+}
+
+function upgrade_112_to_113() {
+ global $config;
+
+ if (isset($config['notifications']['smtp']['ssl']) &&
+ $config['notifications']['smtp']['ssl'] == "checked") {
+ $config['notifications']['smtp']['ssl'] = true;
+ } else {
+ unset($config['notifications']['smtp']['ssl']);
+ }
+
+ if (isset($config['notifications']['smtp']['tls']) &&
+ $config['notifications']['smtp']['tls'] == "checked") {
+ $config['notifications']['smtp']['tls'] = true;
+ } else {
+ unset($config['notifications']['smtp']['tls']);
+ }
+}
+
+function upgrade_113_to_114() {
+ global $config;
+
+ if (!isset($config['ipsec']['phase1']) ||
+ !is_array($config['ipsec']['phase1'])) {
+ return;
+ }
+
+ foreach ($config['ipsec']['phase1'] as &$ph1ent) {
+ if (!isset($ph1ent['iketype'])) {
+ $ph1ent['iketype'] = 'ikev1';
+ }
+ }
+}
+
+function upgrade_114_to_115() {
+ global $config;
+
+ if (isset($config['unbound']['custom_options'])) {
+ $config['unbound']['custom_options'] = base64_encode($config['unbound']['custom_options']);
+ }
+}
+
+function upgrade_115_to_116() {
+ global $config;
+
+ if (!is_array($config['ipsec']) || !is_array($config['ipsec']['phase2'])) {
+ return;
+ }
+
+ $keyid = 1;
+ foreach ($config['ipsec']['phase2'] as $idx => $ph2) {
+ $config['ipsec']['phase2'][$idx]['reqid'] = $keyid;
+ $keyid++;
+ }
+}
+
+function upgrade_116_to_117() {
+ global $config;
+
+ if (!isset($config['ipsec']['client']) ||
+ !isset($config['ipsec']['client']['dns_split']) ||
+ empty($config['ipsec']['client']['dns_split'])) {
+ return;
+ }
+
+ $config['ipsec']['client']['dns_split'] =
+ preg_replace('/\s*,\s*/', ' ', trim($config['ipsec']['client']['dns_split']));
+
+}
+
+function upgrade_117_to_118() {
+ global $config;
+
+ // Unset any old CA and Cert in the system section that might still be there from when upgrade_066_to_067 did not unset them.
+ if (isset($config['system']['ca'])) {
+ unset($config['system']['ca']);
+ }
+ if (isset($config['system']['cert'])) {
+ unset($config['system']['cert']);
+ }
+
+ if (!isset($config['ipsec']['phase1'])) {
+ return;
+ }
+
+ $a_phase1 =& $config['ipsec']['phase1'];
+
+ foreach ($a_phase1 as &$ph1_entry) {
+ // update asn1dn strings from racoon's format to strongswan's
+ if (isset($ph1_entry['myid_type']) && $ph1_entry['myid_type'] == 'asn1dn') {
+ $ph1_entry['myid_data'] =
+ preg_replace('/\/\s*emailAddress\s*=\s*/', ', E=', $ph1_entry['myid_data']);
+ }
+ if (isset($ph1_entry['peerid_type']) && $ph1_entry['peerid_type'] == 'asn1dn') {
+ $ph1_entry['peerid_data'] =
+ preg_replace('/\/\s*emailAddress\s*=\s*/', ', E=', $ph1_entry['peerid_data']);
+ }
+ // iketype 'auto' was removed and is really v2, update accordingly
+ if ($ph1_entry['iketype'] == "auto") {
+ $ph1_entry['iketype'] = "ikev2";
+ }
+ }
+}
+
+function upgrade_118_to_119() {
+ global $config;
+
+ if (!isset($config['ipsec']['phase1'])) {
+ return;
+ }
+
+ // change peerid_type to 'any' for EAP types to retain previous behavior of omitting rightid
+ $a_phase1 =& $config['ipsec']['phase1'];
+
+ foreach ($a_phase1 as &$ph1_entry) {
+ if (strstr($ph1_entry['authentication_method'], 'eap')) {
+ $ph1_entry['peerid_type'] = "any";
+ }
+ }
+}
+
+function upgrade_119_to_120() {
+ global $config;
+
+ if (!isset($config['installedpackages']['miniupnpd']['config'][0])) {
+ return;
+ }
+
+ $miniupnpd =& $config['installedpackages']['miniupnpd']['config'][0];
+
+ $miniupnpd['row'] = array();
+
+ for ($i = 1; $i <= 4; $i++) {
+ if (isset($miniupnpd["permuser{$i}"]) && !empty($miniupnpd["permuser{$i}"])) {
+ $miniupnpd['row'][] = array('permuser' => $miniupnpd["permuser{$i}"]);
+ }
+ unset($miniupnpd["permuser{$i}"]);
+ }
+}
+
+?>
diff --git a/src/etc/inc/util.inc b/src/etc/inc/util.inc
new file mode 100644
index 0000000..b2c797b
--- /dev/null
+++ b/src/etc/inc/util.inc
@@ -0,0 +1,2259 @@
+<?php
+/*
+ util.inc
+ part of the pfSense project (https://www.pfsense.org)
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /bin/ps /bin/kill /usr/bin/killall /sbin/ifconfig /usr/bin/netstat
+ pfSense_BUILDER_BINARIES: /usr/bin/awk /sbin/dmesg /sbin/ping /usr/local/sbin/gzsig /usr/sbin/arp
+ pfSense_BUILDER_BINARIES: /sbin/conscontrol /sbin/devd /bin/ps
+ pfSense_MODULE: utils
+*/
+
+/* kill a process by pid file */
+function killbypid($pidfile) {
+ return sigkillbypid($pidfile, "TERM");
+}
+
+function isvalidpid($pidfile) {
+ $output = "";
+ if (file_exists($pidfile)) {
+ exec("/bin/pgrep -nF {$pidfile}", $output, $retval);
+ return (intval($retval) == 0);
+ }
+ return false;
+}
+
+function is_process_running($process) {
+ $output = "";
+ exec("/bin/pgrep -anx " . escapeshellarg($process), $output, $retval);
+
+ return (intval($retval) == 0);
+}
+
+function isvalidproc($proc) {
+ return is_process_running($proc);
+}
+
+/* sigkill a process by pid file */
+/* return 1 for success and 0 for a failure */
+function sigkillbypid($pidfile, $sig) {
+ if (file_exists($pidfile)) {
+ return mwexec("/bin/pkill " . escapeshellarg("-{$sig}") . " -F {$pidfile}", true);
+ }
+
+ return 0;
+}
+
+/* kill a process by name */
+function sigkillbyname($procname, $sig) {
+ if (isvalidproc($procname)) {
+ return mwexec("/usr/bin/killall " . escapeshellarg("-{$sig}") . " " . escapeshellarg($procname), true);
+ }
+}
+
+/* kill a process by name */
+function killbyname($procname) {
+ if (isvalidproc($procname)) {
+ mwexec("/usr/bin/killall " . escapeshellarg($procname));
+ }
+}
+
+function is_subsystem_dirty($subsystem = "") {
+ global $g;
+
+ if ($subsystem == "") {
+ return false;
+ }
+
+ if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty")) {
+ return true;
+ }
+
+ return false;
+}
+
+function mark_subsystem_dirty($subsystem = "") {
+ global $g;
+
+ if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY")) {
+ log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
+ }
+}
+
+function clear_subsystem_dirty($subsystem = "") {
+ global $g;
+
+ @unlink("{$g['varrun_path']}/{$subsystem}.dirty");
+}
+
+function config_lock() {
+ return;
+}
+function config_unlock() {
+ return;
+}
+
+/* lock configuration file */
+function lock($lock, $op = LOCK_SH) {
+ global $g, $cfglckkeyconsumers;
+ if (!$lock) {
+ die(gettext("WARNING: You must give a name as parameter to lock() function."));
+ }
+ if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
+ @touch("{$g['tmp_path']}/{$lock}.lock");
+ @chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
+ }
+ $cfglckkeyconsumers++;
+ if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
+ if (flock($fp, $op)) {
+ return $fp;
+ } else {
+ fclose($fp);
+ }
+ }
+}
+
+function try_lock($lock, $timeout = 5) {
+ global $g, $cfglckkeyconsumers;
+ if (!$lock) {
+ die(gettext("WARNING: You must give a name as parameter to try_lock() function."));
+ }
+ if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
+ @touch("{$g['tmp_path']}/{$lock}.lock");
+ @chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
+ }
+ $cfglckkeyconsumers++;
+ if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
+ $trycounter = 0;
+ while (!flock($fp, LOCK_EX | LOCK_NB)) {
+ if ($trycounter >= $timeout) {
+ fclose($fp);
+ return NULL;
+ }
+ sleep(1);
+ $trycounter++;
+ }
+
+ return $fp;
+ }
+
+ return NULL;
+}
+
+/* unlock configuration file */
+function unlock($cfglckkey = 0) {
+ global $g, $cfglckkeyconsumers;
+ flock($cfglckkey, LOCK_UN);
+ fclose($cfglckkey);
+ return;
+}
+
+/* unlock forcefully configuration file */
+function unlock_force($lock) {
+ global $g;
+
+ @unlink("{$g['tmp_path']}/{$lock}.lock");
+}
+
+function send_event($cmd) {
+ global $g;
+
+ if (!isset($g['event_address'])) {
+ $g['event_address'] = "unix:///var/run/check_reload_status";
+ }
+
+ $try = 0;
+ while ($try < 3) {
+ $fd = @fsockopen($g['event_address']);
+ if ($fd) {
+ fwrite($fd, $cmd);
+ $resp = fread($fd, 4096);
+ if ($resp != "OK\n") {
+ log_error("send_event: sent {$cmd} got {$resp}");
+ }
+ fclose($fd);
+ $try = 3;
+ } else if (!is_process_running("check_reload_status")) {
+ mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
+ }
+ $try++;
+ }
+}
+
+function send_multiple_events($cmds) {
+ global $g;
+
+ if (!isset($g['event_address'])) {
+ $g['event_address'] = "unix:///var/run/check_reload_status";
+ }
+
+ if (!is_array($cmds)) {
+ return;
+ }
+
+ while ($try < 3) {
+ $fd = @fsockopen($g['event_address']);
+ if ($fd) {
+ foreach ($cmds as $cmd) {
+ fwrite($fd, $cmd);
+ $resp = fread($fd, 4096);
+ if ($resp != "OK\n") {
+ log_error("send_event: sent {$cmd} got {$resp}");
+ }
+ }
+ fclose($fd);
+ $try = 3;
+ } else if (!is_process_running("check_reload_status")) {
+ mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
+ }
+ $try++;
+ }
+}
+
+function refcount_init($reference) {
+ $shmid = @shmop_open($reference, "c", 0644, 10);
+ @shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
+ @shmop_close($shmid);
+}
+
+function refcount_reference($reference) {
+ /* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
+ $shm_lck = lock("shm{$reference}", LOCK_EX);
+ try {
+ /* NOTE: A warning is generated when shared memory does not exist */
+ $shmid = @shmop_open($reference, "w", 0, 0);
+ if (!$shmid) {
+ refcount_init($reference);
+ $shmid = @shmop_open($reference, "w", 0, 0);
+ if (!$shmid) {
+ log_error(gettext("Could not open shared memory {$reference}"));
+ unlock($shm_lck);
+ return;
+ }
+ }
+ $shm_data = @shmop_read($shmid, 0, 10);
+ $shm_data = intval($shm_data) + 1;
+ @shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
+ @shmop_close($shmid);
+ unlock($shm_lck);
+ } catch (Exception $e) {
+ log_error($e->getMessage());
+ unlock($shm_lck);
+ }
+
+ return $shm_data;
+}
+
+function refcount_unreference($reference) {
+ /* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
+ $shm_lck = lock("shm{$reference}", LOCK_EX);
+ try {
+ $shmid = @shmop_open($reference, "w", 0, 0);
+ if (!$shmid) {
+ refcount_init($reference);
+ log_error(gettext("Could not open shared memory {$reference}"));
+ unlock($shm_lck);
+ return;
+ }
+ $shm_data = @shmop_read($shmid, 0, 10);
+ $shm_data = intval($shm_data) - 1;
+ if ($shm_data < 0) {
+ //debug_backtrace();
+ log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
+ } else {
+ @shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
+ }
+ @shmop_close($shmid);
+ unlock($shm_lck);
+ } catch (Exception $e) {
+ log_error($e->getMessage());
+ unlock($shm_lck);
+ }
+
+ return $shm_data;
+}
+
+function refcount_read($reference) {
+ /* This function just reads the current value of the refcount for information. */
+ /* There is no need for locking. */
+ $shmid = @shmop_open($reference, "a", 0, 0);
+ if (!$shmid) {
+ log_error(gettext("Could not open shared memory for read {$reference}"));
+ return -1;
+ }
+ $shm_data = @shmop_read($shmid, 0, 10);
+ @shmop_close($shmid);
+ return $shm_data;
+}
+
+function is_module_loaded($module_name) {
+ $module_name = str_replace(".ko", "", $module_name);
+ $running = 0;
+ $_gb = exec("/sbin/kldstat -qn {$module_name} 2>&1", $_gb, $running);
+ if (intval($running) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* validate non-negative numeric string, or equivalent numeric variable */
+function is_numericint($arg) {
+ return (((is_int($arg) && $arg >= 0) || (is_string($arg) && strlen($arg) > 0 && ctype_digit($arg))) ? true : false);
+}
+
+/* Generate the (human readable) ipv4 or ipv6 subnet address (i.e., netmask, or subnet start IP)
+ given an (human readable) ipv4 or ipv6 host address and subnet bit count */
+function gen_subnet($ipaddr, $bits) {
+ if (($sn = gen_subnetv6($ipaddr, $bits)) == '') {
+ $sn = gen_subnetv4($ipaddr, $bits); // try to avoid rechecking IPv4/v6
+ }
+ return $sn;
+}
+
+/* same as gen_subnet() but accepts IPv4 only */
+function gen_subnetv4($ipaddr, $bits) {
+ if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
+ if ($bits == 0) {
+ return '0.0.0.0'; // avoids <<32
+ }
+ return long2ip(ip2long($ipaddr) & ((0xFFFFFFFF << (32 - $bits)) & 0xFFFFFFFF));
+ }
+ return "";
+}
+
+/* same as gen_subnet() but accepts IPv6 only */
+function gen_subnetv6($ipaddr, $bits) {
+ if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
+ return Net_IPv6::compress(Net_IPv6::getNetmask($ipaddr, $bits));
+ }
+ return "";
+}
+
+/* Generate the (human readable) ipv4 or ipv6 subnet end address (i.e., highest address, end IP, or IPv4 broadcast address)
+ given an (human readable) ipv4 or ipv6 host address and subnet bit count. */
+function gen_subnet_max($ipaddr, $bits) {
+ if (($sn = gen_subnetv6_max($ipaddr, $bits)) == '') {
+ $sn = gen_subnetv4_max($ipaddr, $bits); // try to avoid rechecking IPv4/v6
+ }
+ return $sn;
+}
+
+/* same as gen_subnet_max() but validates IPv4 only */
+function gen_subnetv4_max($ipaddr, $bits) {
+ if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
+ if ($bits == 32) {
+ return $ipaddr;
+ }
+ return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
+ }
+ return "";
+}
+
+/* same as gen_subnet_max() but validates IPv6 only */
+function gen_subnetv6_max($ipaddr, $bits) {
+ if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
+ $endip_bin = substr(Net_IPv6::_ip2Bin($ipaddr), 0, $bits) . str_repeat('1', 128 - $bits);
+ return Net_IPv6::compress(Net_IPv6::_bin2Ip($endip_bin));
+ }
+ return "";
+}
+
+/* returns a subnet mask (long given a bit count) */
+function gen_subnet_mask_long($bits) {
+ $sm = 0;
+ for ($i = 0; $i < $bits; $i++) {
+ $sm >>= 1;
+ $sm |= 0x80000000;
+ }
+ return $sm;
+}
+
+/* same as above but returns a string */
+function gen_subnet_mask($bits) {
+ return long2ip(gen_subnet_mask_long($bits));
+}
+
+/* Convert long int to IP address, truncating to 32-bits. */
+function long2ip32($ip) {
+ return long2ip($ip & 0xFFFFFFFF);
+}
+
+/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
+function ip2long32($ip) {
+ return (ip2long($ip) & 0xFFFFFFFF);
+}
+
+/* Convert IP address to unsigned long int. */
+function ip2ulong($ip) {
+ return sprintf("%u", ip2long32($ip));
+}
+
+/* Find out how many IPs are contained within a given IP range
+ * e.g. 192.168.0.0 to 192.168.0.255 returns 256
+ */
+function ip_range_size_v4($startip, $endip) {
+ if (is_ipaddrv4($startip) && is_ipaddrv4($endip)) {
+ // Operate as unsigned long because otherwise it wouldn't work
+ // when crossing over from 127.255.255.255 / 128.0.0.0 barrier
+ return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
+ }
+ return -1;
+}
+
+/* Find the smallest possible subnet mask which can contain a given number of IPs
+ * e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
+ */
+function find_smallest_cidr_v4($number) {
+ $smallest = 1;
+ for ($b=32; $b > 0; $b--) {
+ $smallest = ($number <= pow(2, $b)) ? $b : $smallest;
+ }
+ return (32-$smallest);
+}
+
+/* Return the previous IP address before the given address */
+function ip_before($ip, $offset = 1) {
+ return long2ip32(ip2long($ip) - $offset);
+}
+
+/* Return the next IP address after the given address */
+function ip_after($ip, $offset = 1) {
+ return long2ip32(ip2long($ip) + $offset);
+}
+
+/* Return true if the first IP is 'before' the second */
+function ip_less_than($ip1, $ip2) {
+ // Compare as unsigned long because otherwise it wouldn't work when
+ // crossing over from 127.255.255.255 / 128.0.0.0 barrier
+ return ip2ulong($ip1) < ip2ulong($ip2);
+}
+
+/* Return true if the first IP is 'after' the second */
+function ip_greater_than($ip1, $ip2) {
+ // Compare as unsigned long because otherwise it wouldn't work
+ // when crossing over from 127.255.255.255 / 128.0.0.0 barrier
+ return ip2ulong($ip1) > ip2ulong($ip2);
+}
+
+/* compare two IP addresses */
+function ipcmp($a, $b) {
+ if (ip_less_than($a, $b)) {
+ return -1;
+ } else if (ip_greater_than($a, $b)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* Convert a range of IPv4 addresses to an array of individual addresses. */
+/* Note: IPv6 ranges are not yet supported here. */
+function ip_range_to_address_array($startip, $endip, $max_size = 5000) {
+ if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
+ return false;
+ }
+
+ if (ip_greater_than($startip, $endip)) {
+ // Swap start and end so we can process sensibly.
+ $temp = $startip;
+ $startip = $endip;
+ $endip = $temp;
+ }
+
+ if (ip_range_size_v4($startip, $endip) > $max_size) {
+ return false;
+ }
+
+ // Container for IP addresses within this range.
+ $rangeaddresses = array();
+ $end_int = ip2ulong($endip);
+ for ($ip_int = ip2ulong($startip); $ip_int <= $end_int; $ip_int++) {
+ $rangeaddresses[] = long2ip($ip_int);
+ }
+
+ return $rangeaddresses;
+}
+
+/* Convert a range of IPv4 addresses to an array of subnets which can contain the range. */
+/* Note: IPv6 ranges are not yet supported here. */
+function ip_range_to_subnet_array($startip, $endip) {
+ if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
+ return array();
+ }
+
+ if (ip_greater_than($startip, $endip)) {
+ // Swap start and end so we can process sensibly.
+ $temp = $startip;
+ $startip = $endip;
+ $endip = $temp;
+ }
+
+ // Container for subnets within this range.
+ $rangesubnets = array();
+
+ // Figure out what the smallest subnet is that holds the number of IPs in the given range.
+ $cidr = find_smallest_cidr_v4(ip_range_size_v4($startip, $endip));
+
+ // Loop here to reduce subnet size and retest as needed. We need to make sure
+ // that the target subnet is wholly contained between $startip and $endip.
+ for ($cidr; $cidr <= 32; $cidr++) {
+ // Find the network and broadcast addresses for the subnet being tested.
+ $targetsub_min = gen_subnet($startip, $cidr);
+ $targetsub_max = gen_subnet_max($startip, $cidr);
+
+ // Check best case where the range is exactly one subnet.
+ if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
+ // Hooray, the range is exactly this subnet!
+ return array("{$startip}/{$cidr}");
+ }
+
+ // These remaining scenarios will find a subnet that uses the largest
+ // chunk possible of the range being tested, and leave the rest to be
+ // tested recursively after the loop.
+
+ // Check if the subnet begins with $startip and ends before $endip
+ if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
+ break;
+ }
+
+ // Check if the subnet ends at $endip and starts after $startip
+ if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
+ break;
+ }
+
+ // Check if the subnet is between $startip and $endip
+ if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
+ break;
+ }
+ }
+
+ // Some logic that will recursively search from $startip to the first IP before the start of the subnet we just found.
+ // NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
+ if ($startip != $targetsub_min) {
+ $rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
+ }
+
+ // Add in the subnet we found before, to preserve ordering
+ $rangesubnets[] = "{$targetsub_min}/{$cidr}";
+
+ // And some more logic that will search after the subnet we found to fill in to the end of the range.
+ if ($endip != $targetsub_max) {
+ $rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
+ }
+ return $rangesubnets;
+}
+
+/* returns true if $range is a valid pair of IPv4 or IPv6 addresses separated by a "-"
+ false - if not a valid pair
+ true (numeric 4 or 6) - if valid, gives type of addresses */
+function is_iprange($range) {
+ if (substr_count($range, '-') != 1) {
+ return false;
+ }
+ list($ip1, $ip2) = explode ('-', $range);
+ if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) {
+ return 4;
+ }
+ if (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) {
+ return 6;
+ }
+ return false;
+}
+
+/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6
+ false - not valid
+ true (numeric 4 or 6) - if valid, gives type of address */
+function is_ipaddr($ipaddr) {
+ if (is_ipaddrv4($ipaddr)) {
+ return 4;
+ }
+ if (is_ipaddrv6($ipaddr)) {
+ return 6;
+ }
+ return false;
+}
+
+/* returns true if $ipaddr is a valid IPv6 address */
+function is_ipaddrv6($ipaddr) {
+ if (!is_string($ipaddr) || empty($ipaddr)) {
+ return false;
+ }
+ if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
+ $tmpip = explode("%", $ipaddr);
+ $ipaddr = $tmpip[0];
+ }
+ return Net_IPv6::checkIPv6($ipaddr);
+}
+
+/* returns true if $ipaddr is a valid dotted IPv4 address */
+function is_ipaddrv4($ipaddr) {
+ if (!is_string($ipaddr) || empty($ipaddr) || ip2long($ipaddr) === FALSE) {
+ return false;
+ }
+ return true;
+}
+
+/* returns true if $ipaddr is a valid IPv6 linklocal address */
+function is_linklocal($ipaddr) {
+ return (strtolower(substr($ipaddr, 0, 5)) == "fe80:");
+}
+
+/* returns scope of a linklocal address */
+function get_ll_scope($addr) {
+ if (!is_linklocal($addr) || !strstr($addr, "%")) {
+ return "";
+ }
+ list ($ll, $scope) = explode("%", $addr);
+ return $scope;
+}
+
+/* returns true if $ipaddr is a valid literal IPv6 address */
+function is_literalipaddrv6($ipaddr) {
+ if (preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match)) {
+ $ipaddr = $match[1];
+ } else {
+ return false;
+ }
+
+ return is_ipaddrv6($ipaddr);
+}
+
+/* returns true if $iport is a valid IPv4/IPv6 address + port
+ false - not valid
+ true (numeric 4 or 6) - if valid, gives type of address */
+function is_ipaddrwithport($ipport) {
+ $c = strrpos($ipport, ":");
+ if ($c === false) {
+ return false; // can't split at final colon if no colon exists
+ }
+
+ if (!is_port(substr($ipport, $c + 1))) {
+ return false; // no valid port after last colon
+ }
+
+ $ip = substr($ipport, 0, $c); // else is text before last colon a valid IP
+ if (is_literalipaddrv6($ip)) {
+ return 6;
+ } elseif (is_ipaddrv4($ip)) {
+ return 4;
+ } else {
+ return false;
+ }
+}
+
+function is_hostnamewithport($hostport) {
+ $parts = explode(":", $hostport);
+ $port = array_pop($parts);
+ if (count($parts) == 1) {
+ return is_hostname($parts[0]) && is_port($port);
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
+function is_ipaddroralias($ipaddr) {
+ global $config;
+
+ if (is_alias($ipaddr)) {
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type'])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return is_ipaddr($ipaddr);
+ }
+
+}
+
+/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
+ false - if not a valid subnet
+ true (numeric 4 or 6) - if valid, gives type of subnet */
+function is_subnet($subnet) {
+ if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
+ if (is_ipaddrv4($parts[1]) && $parts[3] <= 32) {
+ return 4;
+ }
+ if (is_ipaddrv6($parts[2]) && $parts[3] <= 128) {
+ return 6;
+ }
+ }
+ return false;
+}
+
+/* same as is_subnet() but accepts IPv4 only */
+function is_subnetv4($subnet) {
+ return (is_subnet($subnet) == 4);
+}
+
+/* same as is_subnet() but accepts IPv6 only */
+function is_subnetv6($subnet) {
+ return (is_subnet($subnet) == 6);
+}
+
+/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
+function is_subnetoralias($subnet) {
+ global $aliastable;
+
+ if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet])) {
+ return true;
+ } else {
+ return is_subnet($subnet);
+ }
+}
+
+function subnet_size($subnet) {
+ if (is_subnetv4($subnet)) {
+ list ($ip, $bits) = explode("/", $subnet);
+ return round(exp(log(2) * (32 - $bits)));
+ }
+ else if (is_subnetv6($subnet)) {
+ list ($ip, $bits) = explode("/", $subnet);
+ return round(exp(log(2) * (128 - $bits)));
+ }
+ else {
+ return 0;
+ }
+}
+
+
+function subnet_expand($subnet) {
+ if (is_subnetv4($subnet)) {
+ return subnetv4_expand($subnet);
+ } else if (is_subnetv6($subnet)) {
+ return subnetv6_expand($subnet);
+ } else {
+ return $subnet;
+ }
+}
+
+function subnetv4_expand($subnet) {
+ $result = array();
+ list ($ip, $bits) = explode("/", $subnet);
+ $net = ip2long($ip);
+ $mask = (0xffffffff << (32 - $bits));
+ $net &= $mask;
+ $size = round(exp(log(2) * (32 - $bits)));
+ for ($i = 0; $i < $size; $i += 1) {
+ $result[] = long2ip($net | $i);
+ }
+ return $result;
+}
+
+/* find out whether two subnets overlap */
+function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
+
+ if (!is_numeric($bits1)) {
+ $bits1 = 32;
+ }
+ if (!is_numeric($bits2)) {
+ $bits2 = 32;
+ }
+
+ if ($bits1 < $bits2) {
+ $relbits = $bits1;
+ } else {
+ $relbits = $bits2;
+ }
+
+ $sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
+ $sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
+
+ return ($sn1 == $sn2);
+}
+
+/* find out whether two IPv6 subnets overlap */
+function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
+ $sub1_min = gen_subnetv6($subnet1, $bits1);
+ $sub1_max = gen_subnetv6_max($subnet1, $bits1);
+ $sub2_min = gen_subnetv6($subnet2, $bits2);
+ $sub2_max = gen_subnetv6_max($subnet2, $bits2);
+
+ return (is_inrange_v6($sub1_min, $sub2_min, $sub2_max) || is_inrange_v6($sub1_max, $sub2_min, $sub2_max) || is_inrange_v6($sub2_min, $sub1_min, $sub1_max));
+}
+
+/* return true if $addr is in $subnet, false if not */
+function ip_in_subnet($addr, $subnet) {
+ if (is_ipaddrv6($addr) && is_subnetv6($subnet)) {
+ return (Net_IPv6::isInNetmask($addr, $subnet));
+ } else if (is_ipaddrv4($addr) && is_subnetv4($subnet)) {
+ list($ip, $mask) = explode('/', $subnet);
+ $mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
+ return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
+ }
+ return false;
+}
+
+/* returns true if $hostname is just a valid hostname (top part without any of the domain part) */
+function is_unqualified_hostname($hostname) {
+ if (!is_string($hostname)) {
+ return false;
+ }
+
+ if (preg_match('/^(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $hostname is a valid hostname, with or without being a fully-qualified domain name. */
+function is_hostname($hostname) {
+ if (!is_string($hostname)) {
+ return false;
+ }
+
+ if (is_domain($hostname)) {
+ if ((substr_count($hostname, ".") == 1) && ($hostname[strlen($hostname)-1] == ".")) {
+ /* Only a single dot at the end like "test." - hosts cannot be directly in the root domain. */
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $domain is a valid domain name */
+function is_domain($domain) {
+ if (!is_string($domain)) {
+ return false;
+ }
+
+ if (preg_match('/^(?:(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9])\.)*(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9\.])$/i', $domain)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $macaddr is a valid MAC address */
+function is_macaddr($macaddr, $partial=false) {
+ $repeat = ($partial) ? '1,5' : '5';
+ return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
+}
+
+/* returns true if $name is a valid name for an alias
+ returns NULL if a reserved word is used
+ returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
+ aliases cannot be:
+ bad chars: anything except a-z 0-9 and underscore
+ bad names: empty string, pure numeric, pure underscore
+ reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and "pass" */
+
+function is_validaliasname($name) {
+ /* Array of reserved words */
+ $reserved = array("port", "pass");
+
+ if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name)) {
+ return false;
+ }
+ if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name)) {
+ return; /* return NULL */
+ }
+ return true;
+}
+
+/* returns true if $port is a valid TCP/UDP port */
+function is_port($port) {
+ if (ctype_digit($port) && ((intval($port) >= 1) && (intval($port) <= 65535))) {
+ return true;
+ }
+ if (getservbyname($port, "tcp") || getservbyname($port, "udp")) {
+ return true;
+ }
+ return false;
+}
+
+/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
+function is_portrange($portrange) {
+ $ports = explode(":", $portrange);
+
+ return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
+}
+
+/* returns true if $port is a valid port number or an alias thereof */
+function is_portoralias($port) {
+ global $config;
+
+ if (is_alias($port)) {
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if ($alias['name'] == $port && preg_match("/port/i", $alias['type'])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return is_port($port);
+ }
+}
+
+/* create ranges of sequential port numbers (200:215) and remove duplicates */
+function group_ports($ports) {
+ if (!is_array($ports) || empty($ports)) {
+ return;
+ }
+
+ $uniq = array();
+ foreach ($ports as $port) {
+ if (is_portrange($port)) {
+ list($begin, $end) = explode(":", $port);
+ if ($begin > $end) {
+ $aux = $begin;
+ $begin = $end;
+ $end = $aux;
+ }
+ for ($i = $begin; $i <= $end; $i++) {
+ if (!in_array($i, $uniq)) {
+ $uniq[] = $i;
+ }
+ }
+ } else if (is_port($port)) {
+ if (!in_array($port, $uniq)) {
+ $uniq[] = $port;
+ }
+ }
+ }
+ sort($uniq, SORT_NUMERIC);
+
+ $result = array();
+ foreach ($uniq as $idx => $port) {
+ if ($idx == 0) {
+ $result[] = $port;
+ continue;
+ }
+
+ $last = end($result);
+ if (is_portrange($last)) {
+ list($begin, $end) = explode(":", $last);
+ } else {
+ $begin = $end = $last;
+ }
+
+ if ($port == ($end+1)) {
+ $end++;
+ $result[count($result)-1] = "{$begin}:{$end}";
+ } else {
+ $result[] = $port;
+ }
+ }
+
+ return $result;
+}
+
+/* returns true if $val is a valid shaper bandwidth value */
+function is_valid_shaperbw($val) {
+ return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
+}
+
+/* returns true if $test is in the range between $start and $end */
+function is_inrange_v4($test, $start, $end) {
+ if ((ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $test is in the range between $start and $end */
+function is_inrange_v6($test, $start, $end) {
+ if ((inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* returns true if $test is in the range between $start and $end */
+function is_inrange($test, $start, $end) {
+ return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
+}
+
+/* XXX: return the configured carp interface list */
+function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
+ global $config;
+
+ $iflist = array();
+
+ if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ switch ($vip['mode']) {
+ case "carp":
+ if (!empty($carpinterface)) {
+ if ($carpinterface == "_vip{$vip['uniqid']}") {
+ switch ($what) {
+ case 'subnet':
+ if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
+ return $vip['subnet_bits'];
+ } else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
+ return $vip['subnet_bits'];
+ }
+ break;
+ case 'iface':
+ if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
+ return $vip['interface'];
+ } else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
+ return $vip['interface'];
+ }
+ break;
+ case 'vip':
+ if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
+ return $vip;
+ } else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
+ return $vip;
+ }
+ break;
+ case 'ip':
+ default:
+ if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
+ return $vip['subnet'];
+ } else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
+ return $vip['subnet'];
+ }
+ break;
+ }
+ }
+ } else {
+ $iflist["_vip{$vip['uniqid']}"] = $vip['subnet'];
+ }
+ break;
+ }
+ }
+ }
+
+ return $iflist;
+}
+
+/* return the configured IP aliases list */
+function get_configured_ip_aliases_list($returnfullentry = false) {
+ global $config;
+
+ $alias_list = array();
+
+ if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ if ($vip['mode'] == "ipalias") {
+ if ($returnfullentry) {
+ $alias_list[$vip['subnet']] = $vip;
+ } else {
+ $alias_list[$vip['subnet']] = $vip['interface'];
+ }
+ }
+ }
+ }
+
+ return $alias_list;
+}
+
+/* return all configured aliases list (IP, carp, proxyarp and other) */
+function get_configured_vips_list() {
+ global $config;
+
+ $alias_list = array();
+
+ if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ if ($vip['mode'] == "carp") {
+ $alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
+ } else {
+ $alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
+ }
+ }
+ }
+
+ return $alias_list;
+}
+
+/* comparison function for sorting by the order in which interfaces are normally created */
+function compare_interface_friendly_names($a, $b) {
+ if ($a == $b) {
+ return 0;
+ } else if ($a == 'wan') {
+ return -1;
+ } else if ($b == 'wan') {
+ return 1;
+ } else if ($a == 'lan') {
+ return -1;
+ } else if ($b == 'lan') {
+ return 1;
+ }
+
+ return strnatcmp($a, $b);
+}
+
+/* return the configured interfaces list. */
+function get_configured_interface_list($only_opt = false, $withdisabled = false) {
+ global $config;
+
+ $iflist = array();
+
+ /* if list */
+ foreach ($config['interfaces'] as $if => $ifdetail) {
+ if ($only_opt && ($if == "wan" || $if == "lan")) {
+ continue;
+ }
+ if (isset($ifdetail['enable']) || $withdisabled == true) {
+ $iflist[$if] = $if;
+ }
+ }
+
+ return $iflist;
+}
+
+/* return the configured interfaces list. */
+function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
+ global $config;
+
+ $iflist = array();
+
+ /* if list */
+ foreach ($config['interfaces'] as $if => $ifdetail) {
+ if ($only_opt && ($if == "wan" || $if == "lan")) {
+ continue;
+ }
+ if (isset($ifdetail['enable']) || $withdisabled == true) {
+ $tmpif = get_real_interface($if);
+ if (!empty($tmpif)) {
+ $iflist[$tmpif] = $if;
+ }
+ }
+ }
+
+ return $iflist;
+}
+
+/* return the configured interfaces list with their description. */
+function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
+ global $config;
+
+ $iflist = array();
+
+ /* if list */
+ foreach ($config['interfaces'] as $if => $ifdetail) {
+ if ($only_opt && ($if == "wan" || $if == "lan")) {
+ continue;
+ }
+ if (isset($ifdetail['enable']) || $withdisabled == true) {
+ if (empty($ifdetail['descr'])) {
+ $iflist[$if] = strtoupper($if);
+ } else {
+ $iflist[$if] = strtoupper($ifdetail['descr']);
+ }
+ }
+ }
+
+ return $iflist;
+}
+
+/*
+ * get_configured_ip_addresses() - Return a list of all configured
+ * interfaces IP Addresses
+ *
+ */
+function get_configured_ip_addresses() {
+ global $config;
+
+ if (!function_exists('get_interface_ip')) {
+ require_once("interfaces.inc");
+ }
+ $ip_array = array();
+ $interfaces = get_configured_interface_list();
+ if (is_array($interfaces)) {
+ foreach ($interfaces as $int) {
+ $ipaddr = get_interface_ip($int);
+ $ip_array[$int] = $ipaddr;
+ }
+ }
+ $interfaces = get_configured_carp_interface_list();
+ if (is_array($interfaces)) {
+ foreach ($interfaces as $int => $ipaddr) {
+ $ip_array[$int] = $ipaddr;
+ }
+ }
+
+ /* pppoe server */
+ if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ if ($pppoe['mode'] == "server") {
+ if (is_ipaddr($pppoe['localip'])) {
+ $int = "pppoes". $pppoe['pppoeid'];
+ $ip_array[$int] = $pppoe['localip'];
+ }
+ }
+ }
+ }
+
+ return $ip_array;
+}
+
+/*
+ * get_configured_ipv6_addresses() - Return a list of all configured
+ * interfaces IPv6 Addresses
+ *
+ */
+function get_configured_ipv6_addresses() {
+ require_once("interfaces.inc");
+ $ipv6_array = array();
+ $interfaces = get_configured_interface_list();
+ if (is_array($interfaces)) {
+ foreach ($interfaces as $int) {
+ $ipaddrv6 = get_interface_ipv6($int);
+ $ipv6_array[$int] = $ipaddrv6;
+ }
+ }
+ $interfaces = get_configured_carp_interface_list();
+ if (is_array($interfaces)) {
+ foreach ($interfaces as $int => $ipaddrv6) {
+ $ipv6_array[$int] = $ipaddrv6;
+ }
+ }
+ return $ipv6_array;
+}
+
+/*
+ * get_interface_list() - Return a list of all physical interfaces
+ * along with MAC and status.
+ *
+ * $mode = "active" - use ifconfig -lu
+ * "media" - use ifconfig to check physical connection
+ * status (much slower)
+ */
+function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
+ global $config;
+ $upints = array();
+ /* get a list of virtual interface types */
+ if (!$vfaces) {
+ $vfaces = array(
+ 'bridge',
+ 'ppp',
+ 'pppoe',
+ 'pptp',
+ 'l2tp',
+ 'sl',
+ 'gif',
+ 'gre',
+ 'faith',
+ 'lo',
+ 'ng',
+ '_vlan',
+ '_wlan',
+ 'pflog',
+ 'plip',
+ 'pfsync',
+ 'enc',
+ 'tun',
+ 'carp',
+ 'lagg',
+ 'vip',
+ 'ipfw'
+ );
+ }
+ switch ($mode) {
+ case "active":
+ $upints = pfSense_interface_listget(IFF_UP);
+ break;
+ case "media":
+ $intlist = pfSense_interface_listget();
+ $ifconfig = "";
+ exec("/sbin/ifconfig -a", $ifconfig);
+ $regexp = '/(' . implode('|', $intlist) . '):\s/';
+ $ifstatus = preg_grep('/status:/', $ifconfig);
+ foreach ($ifstatus as $status) {
+ $int = array_shift($intlist);
+ if (stristr($status, "active")) {
+ $upints[] = $int;
+ }
+ }
+ break;
+ default:
+ $upints = pfSense_interface_listget();
+ break;
+ }
+ /* build interface list with netstat */
+ $linkinfo = "";
+ exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
+ array_shift($linkinfo);
+ /* build ip address list with netstat */
+ $ipinfo = "";
+ exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
+ array_shift($ipinfo);
+ foreach ($linkinfo as $link) {
+ $friendly = "";
+ $alink = explode(" ", $link);
+ $ifname = rtrim(trim($alink[0]), '*');
+ /* trim out all numbers before checking for vfaces */
+ if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
+ !stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
+ $toput = array(
+ "mac" => trim($alink[1]),
+ "up" => in_array($ifname, $upints)
+ );
+ foreach ($ipinfo as $ip) {
+ $aip = explode(" ", $ip);
+ if ($aip[0] == $ifname) {
+ $toput['ipaddr'] = $aip[1];
+ }
+ }
+ if (is_array($config['interfaces'])) {
+ foreach ($config['interfaces'] as $name => $int) {
+ if ($int['if'] == $ifname) {
+ $friendly = $name;
+ }
+ }
+ }
+ switch ($keyby) {
+ case "physical":
+ if ($friendly != "") {
+ $toput['friendly'] = $friendly;
+ }
+ $dmesg_arr = array();
+ exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
+ preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
+ $toput['dmesg'] = $dmesg[1][0];
+ $iflist[$ifname] = $toput;
+ break;
+ case "ppp":
+
+ case "friendly":
+ if ($friendly != "") {
+ $toput['if'] = $ifname;
+ $iflist[$friendly] = $toput;
+ }
+ break;
+ }
+ }
+ }
+ return $iflist;
+}
+
+/****f* util/log_error
+* NAME
+* log_error - Sends a string to syslog.
+* INPUTS
+* $error - string containing the syslog message.
+* RESULT
+* null
+******/
+function log_error($error) {
+ global $g;
+ $page = $_SERVER['SCRIPT_NAME'];
+ if (empty($page)) {
+ $files = get_included_files();
+ $page = basename($files[0]);
+ }
+ syslog(LOG_ERR, "$page: $error");
+ if ($g['debug']) {
+ syslog(LOG_WARNING, var_dump(debug_backtrace()));
+ }
+ return;
+}
+
+/****f* util/log_auth
+* NAME
+* log_auth - Sends a string to syslog as LOG_AUTH facility
+* INPUTS
+* $error - string containing the syslog message.
+* RESULT
+* null
+******/
+function log_auth($error) {
+ global $g;
+ $page = $_SERVER['SCRIPT_NAME'];
+ syslog(LOG_AUTH, "$page: $error");
+ if ($g['debug']) {
+ syslog(LOG_WARNING, var_dump(debug_backtrace()));
+ }
+ return;
+}
+
+/****f* util/exec_command
+ * NAME
+ * exec_command - Execute a command and return a string of the result.
+ * INPUTS
+ * $command - String of the command to be executed.
+ * RESULT
+ * String containing the command's result.
+ * NOTES
+ * This function returns the command's stdout and stderr.
+ ******/
+function exec_command($command) {
+ $output = array();
+ exec($command . ' 2>&1', $output);
+ return(implode("\n", $output));
+}
+
+/* wrapper for exec() */
+function mwexec($command, $mute = false, $clearsigmask = false) {
+ global $g;
+
+ if ($g['debug']) {
+ if (!$_SERVER['REMOTE_ADDR']) {
+ echo "mwexec(): $command\n";
+ }
+ }
+ $oarr = array();
+ $retval = 0;
+
+ if ($clearsigmask) {
+ $oldset = array();
+ pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
+ }
+ $garbage = exec("$command 2>&1", $oarr, $retval);
+ if ($clearsigmask) {
+ pcntl_sigprocmask(SIG_SETMASK, $oldset);
+ }
+
+ if (isset($config['system']['developerspew'])) {
+ $mute = false;
+ }
+ if (($retval <> 0) && ($mute === false)) {
+ $output = implode(" ", $oarr);
+ log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
+ unset($output);
+ }
+ unset($oarr);
+ return $retval;
+}
+
+/* wrapper for exec() in background */
+function mwexec_bg($command, $clearsigmask = false) {
+ global $g;
+
+ if ($g['debug']) {
+ if (!$_SERVER['REMOTE_ADDR']) {
+ echo "mwexec(): $command\n";
+ }
+ }
+
+ if ($clearsigmask) {
+ $oldset = array();
+ pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
+ }
+ $_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
+ if ($clearsigmask) {
+ pcntl_sigprocmask(SIG_SETMASK, $oldset);
+ }
+ unset($_gb);
+}
+
+/* unlink a file, if it exists */
+function unlink_if_exists($fn) {
+ $to_do = glob($fn);
+ if (is_array($to_do)) {
+ foreach ($to_do as $filename) {
+ @unlink($filename);
+ }
+ } else {
+ @unlink($fn);
+ }
+}
+/* make a global alias table (for faster lookups) */
+function alias_make_table($config) {
+ global $aliastable;
+
+ $aliastable = array();
+
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if ($alias['name']) {
+ $aliastable[$alias['name']] = $alias['address'];
+ }
+ }
+ }
+}
+
+/* check if an alias exists */
+function is_alias($name) {
+ global $aliastable;
+
+ return isset($aliastable[$name]);
+}
+
+function alias_get_type($name) {
+ global $config;
+
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if ($name == $alias['name']) {
+ return $alias['type'];
+ }
+ }
+ }
+
+ return "";
+}
+
+/* expand a host or network alias, if necessary */
+function alias_expand($name) {
+ global $aliastable;
+
+ if (isset($aliastable[$name])) {
+ // alias names cannot be strictly numeric. redmine #4289
+ if (is_numericint($name)) {
+ return null;
+ }
+ return "\${$name}";
+ } else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name)) {
+ return "{$name}";
+ } else {
+ return null;
+ }
+}
+
+function alias_expand_urltable($name) {
+ global $config;
+ $urltable_prefix = "/var/db/aliastables/";
+ $urltable_filename = $urltable_prefix . $name . ".txt";
+
+ if (is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
+ if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename)) {
+ return $urltable_filename;
+ } else {
+ send_event("service sync alias {$name}");
+ break;
+ }
+ }
+ }
+ }
+ return null;
+}
+
+/* verify (and remove) the digital signature on a file - returns 0 if OK */
+function verify_digital_signature($fname) {
+ global $g;
+
+ if (!file_exists("/usr/local/sbin/gzsig")) {
+ return 4;
+ }
+
+ return mwexec("/usr/local/sbin/gzsig verify {$g['etc_path']}/pubkey.pem < " . escapeshellarg($fname));
+}
+
+/* obtain MAC address given an IP address by looking at the ARP table */
+function arp_get_mac_by_ip($ip) {
+ mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
+ $arpoutput = "";
+ exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
+
+ if ($arpoutput[0]) {
+ $arpi = explode(" ", $arpoutput[0]);
+ $macaddr = $arpi[3];
+ if (is_macaddr($macaddr)) {
+ return $macaddr;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/* return a fieldname that is safe for xml usage */
+function xml_safe_fieldname($fieldname) {
+ $replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
+ ':', ',', '.', '\'', '\\'
+ );
+ return strtolower(str_replace($replace, "", $fieldname));
+}
+
+function mac_format($clientmac) {
+ global $config, $cpzone;
+
+ $mac = explode(":", $clientmac);
+ $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
+
+ switch ($mac_format) {
+ case 'singledash':
+ return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
+
+ case 'ietf':
+ return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
+
+ case 'cisco':
+ return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
+
+ case 'unformatted':
+ return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
+
+ default:
+ return $clientmac;
+ }
+}
+
+function resolve_retry($hostname, $retries = 5) {
+
+ if (is_ipaddr($hostname)) {
+ return $hostname;
+ }
+
+ for ($i = 0; $i < $retries; $i++) {
+ // FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
+ $ip = gethostbyname($hostname);
+
+ if ($ip && $ip != $hostname) {
+ /* success */
+ return $ip;
+ }
+
+ sleep(1);
+ }
+
+ return false;
+}
+
+function format_bytes($bytes) {
+ if ($bytes >= 1073741824) {
+ return sprintf("%.2f GB", $bytes/1073741824);
+ } else if ($bytes >= 1048576) {
+ return sprintf("%.2f MB", $bytes/1048576);
+ } else if ($bytes >= 1024) {
+ return sprintf("%.0f KB", $bytes/1024);
+ } else {
+ return sprintf("%d bytes", $bytes);
+ }
+}
+
+function update_filter_reload_status($text) {
+ global $g;
+
+ file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
+}
+
+/****** util/return_dir_as_array
+ * NAME
+ * return_dir_as_array - Return a directory's contents as an array.
+ * INPUTS
+ * $dir - string containing the path to the desired directory.
+ * $filter_regex - string containing a regular expression to filter file names. Default empty.
+ * RESULT
+ * $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
+ ******/
+function return_dir_as_array($dir, $filter_regex = '') {
+ $dir_array = array();
+ if (is_dir($dir)) {
+ if ($dh = opendir($dir)) {
+ while (($file = readdir($dh)) !== false) {
+ if (($file == ".") || ($file == "..")) {
+ continue;
+ }
+
+ if (empty($filter_regex) || preg_match($filter_regex, $file)) {
+ array_push($dir_array, $file);
+ }
+ }
+ closedir($dh);
+ }
+ }
+ return $dir_array;
+}
+
+function run_plugins($directory) {
+ global $config, $g;
+
+ /* process packager manager custom rules */
+ $files = return_dir_as_array($directory);
+ if (is_array($files)) {
+ foreach ($files as $file) {
+ if (stristr($file, ".sh") == true) {
+ mwexec($directory . $file . " start");
+ } else if (!is_dir($directory . "/" . $file) && stristr($file, ".inc")) {
+ require_once($directory . "/" . $file);
+ }
+ }
+ }
+}
+
+/*
+ * safe_mkdir($path, $mode = 0755)
+ * create directory if it doesn't already exist and isn't a file!
+ */
+function safe_mkdir($path, $mode = 0755) {
+ global $g;
+
+ if (!is_file($path) && !is_dir($path)) {
+ return @mkdir($path, $mode, true);
+ } else {
+ return false;
+ }
+}
+
+/*
+ * get_sysctl($names)
+ * Get values of sysctl OID's listed in $names (accepts an array or a single
+ * name) and return an array of key/value pairs set for those that exist
+ */
+function get_sysctl($names) {
+ if (empty($names)) {
+ return array();
+ }
+
+ if (is_array($names)) {
+ $name_list = array();
+ foreach ($names as $name) {
+ $name_list[] = escapeshellarg($name);
+ }
+ } else {
+ $name_list = array(escapeshellarg($names));
+ }
+
+ exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
+ $values = array();
+ foreach ($output as $line) {
+ $line = explode(": ", $line, 2);
+ if (count($line) == 2) {
+ $values[$line[0]] = $line[1];
+ }
+ }
+
+ return $values;
+}
+
+/*
+ * get_single_sysctl($name)
+ * Wrapper for get_sysctl() to simplify read of a single sysctl value
+ * return the value for sysctl $name or empty string if it doesn't exist
+ */
+function get_single_sysctl($name) {
+ if (empty($name)) {
+ return "";
+ }
+
+ $value = get_sysctl($name);
+ if (empty($value) || !isset($value[$name])) {
+ return "";
+ }
+
+ return $value[$name];
+}
+
+/*
+ * set_sysctl($value_list)
+ * Set sysctl OID's listed as key/value pairs and return
+ * an array with keys set for those that succeeded
+ */
+function set_sysctl($values) {
+ if (empty($values)) {
+ return array();
+ }
+
+ $value_list = array();
+ foreach ($values as $key => $value) {
+ $value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
+ }
+
+ exec("/sbin/sysctl -i " . implode(" ", $value_list), $output, $success);
+
+ /* Retry individually if failed (one or more read-only) */
+ if ($success <> 0 && count($value_list) > 1) {
+ foreach ($value_list as $value) {
+ exec("/sbin/sysctl -i " . $value, $output);
+ }
+ }
+
+ $ret = array();
+ foreach ($output as $line) {
+ $line = explode(": ", $line, 2);
+ if (count($line) == 2) {
+ $ret[$line[0]] = true;
+ }
+ }
+
+ return $ret;
+}
+
+/*
+ * set_single_sysctl($name, $value)
+ * Wrapper to set_sysctl() to make it simple to set only one sysctl
+ * returns boolean meaning if it succeeded
+ */
+function set_single_sysctl($name, $value) {
+ if (empty($name)) {
+ return false;
+ }
+
+ $result = set_sysctl(array($name => $value));
+
+ if (!isset($result[$name]) || $result[$name] != $value) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * get_memory()
+ * returns an array listing the amount of
+ * memory installed in the hardware
+ * [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
+ * [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
+ */
+function get_memory() {
+ $physmem = get_single_sysctl("hw.physmem");
+ $realmem = get_single_sysctl("hw.realmem");
+ /* convert from bytes to megabytes */
+ return array(($physmem/1048576), ($realmem/1048576));
+}
+
+function mute_kernel_msgs() {
+ global $g, $config;
+ // Do not mute serial console. The kernel gets very very cranky
+ // and will start dishing you cannot control tty errors.
+ if ($g['platform'] == 'nanobsd') {
+ return;
+ }
+ if ($config['system']['enableserial']) {
+ return;
+ }
+ exec("/sbin/conscontrol mute on");
+}
+
+function unmute_kernel_msgs() {
+ global $g;
+ // Do not mute serial console. The kernel gets very very cranky
+ // and will start dishing you cannot control tty errors.
+ if ($g['platform'] == 'nanobsd') {
+ return;
+ }
+ exec("/sbin/conscontrol mute off");
+}
+
+function start_devd() {
+ /* Use the undocumented -q options of devd to quiet its log spamming */
+ $_gb = exec("/sbin/devd -q");
+ sleep(1);
+ unset($_gb);
+}
+
+function is_interface_vlan_mismatch() {
+ global $config, $g;
+
+ if (is_array($config['vlans']['vlan'])) {
+ foreach ($config['vlans']['vlan'] as $vlan) {
+ if (does_interface_exist($vlan['if']) == false) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function is_interface_mismatch() {
+ global $config, $g;
+
+ $do_assign = false;
+ $i = 0;
+ $missing_interfaces = array();
+ if (is_array($config['interfaces'])) {
+ foreach ($config['interfaces'] as $ifname => $ifcfg) {
+ if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
+ // Do not check these interfaces.
+ $i++;
+ continue;
+ } else if (does_interface_exist($ifcfg['if']) == false) {
+ $missing_interfaces[] = $ifcfg['if'];
+ $do_assign = true;
+ } else {
+ $i++;
+ }
+ }
+ }
+
+ if (file_exists("{$g['tmp_path']}/assign_complete")) {
+ $do_assign = false;
+ }
+
+ if (!empty($missing_interfaces) && $do_assign) {
+ file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
+ } else {
+ @unlink("{$g['tmp_path']}/missing_interfaces");
+ }
+
+ return $do_assign;
+}
+
+/* sync carp entries to other firewalls */
+function carp_sync_client() {
+ global $g;
+ send_event("filter sync");
+}
+
+/****f* util/isAjax
+ * NAME
+ * isAjax - reports if the request is driven from prototype
+ * INPUTS
+ * none
+ * RESULT
+ * true/false
+ ******/
+function isAjax() {
+ return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
+}
+
+/****f* util/timeout
+ * NAME
+ * timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
+ * INPUTS
+ * optional, seconds to wait before timeout. Default 9 seconds.
+ * RESULT
+ * returns 1 char of user input or null if no input.
+ ******/
+function timeout($timer = 9) {
+ while (!isset($key)) {
+ if ($timer >= 9) {
+ echo chr(8) . chr(8) . ($timer == 9 ? chr(32) : null) . "{$timer}";
+ } else {
+ echo chr(8). "{$timer}";
+ }
+ `/bin/stty -icanon min 0 time 25`;
+ $key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
+ `/bin/stty icanon`;
+ if ($key == '') {
+ unset($key);
+ }
+ $timer--;
+ if ($timer == 0) {
+ break;
+ }
+ }
+ return $key;
+}
+
+/****f* util/msort
+ * NAME
+ * msort - sort array
+ * INPUTS
+ * $array to be sorted, field to sort by, direction of sort
+ * RESULT
+ * returns newly sorted array
+ ******/
+function msort($array, $id = "id", $sort_ascending = true) {
+ $temp_array = array();
+ while (count($array)>0) {
+ $lowest_id = 0;
+ $index = 0;
+ foreach ($array as $item) {
+ if (isset($item[$id])) {
+ if ($array[$lowest_id][$id]) {
+ if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
+ $lowest_id = $index;
+ }
+ }
+ }
+ $index++;
+ }
+ $temp_array[] = $array[$lowest_id];
+ $array = array_merge(array_slice($array, 0, $lowest_id), array_slice($array, $lowest_id + 1));
+ }
+ if ($sort_ascending) {
+ return $temp_array;
+ } else {
+ return array_reverse($temp_array);
+ }
+}
+
+/****f* util/is_URL
+ * NAME
+ * is_URL
+ * INPUTS
+ * string to check
+ * RESULT
+ * Returns true if item is a URL
+ ******/
+function is_URL($url) {
+ $match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
+ if ($match) {
+ return true;
+ }
+ return false;
+}
+
+function is_file_included($file = "") {
+ $files = get_included_files();
+ if (in_array($file, $files)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Replace a value on a deep associative array using regex
+ */
+function array_replace_values_recursive($data, $match, $replace) {
+ if (empty($data)) {
+ return $data;
+ }
+
+ if (is_string($data)) {
+ $data = preg_replace("/{$match}/", $replace, $data);
+ } else if (is_array($data)) {
+ foreach ($data as $k => $v) {
+ $data[$k] = array_replace_values_recursive($v, $match, $replace);
+ }
+ }
+
+ return $data;
+}
+
+/*
+ This function was borrowed from a comment on PHP.net at the following URL:
+ http://www.php.net/manual/en/function.array-merge-recursive.php#73843
+ */
+function array_merge_recursive_unique($array0, $array1) {
+
+ $arrays = func_get_args();
+ $remains = $arrays;
+
+ // We walk through each arrays and put value in the results (without
+ // considering previous value).
+ $result = array();
+
+ // loop available array
+ foreach ($arrays as $array) {
+
+ // The first remaining array is $array. We are processing it. So
+ // we remove it from remaining arrays.
+ array_shift($remains);
+
+ // We don't care non array param, like array_merge since PHP 5.0.
+ if (is_array($array)) {
+ // Loop values
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ // we gather all remaining arrays that have such key available
+ $args = array();
+ foreach ($remains as $remain) {
+ if (array_key_exists($key, $remain)) {
+ array_push($args, $remain[$key]);
+ }
+ }
+
+ if (count($args) > 2) {
+ // put the recursion
+ $result[$key] = call_user_func_array(__FUNCTION__, $args);
+ } else {
+ foreach ($value as $vkey => $vval) {
+ $result[$key][$vkey] = $vval;
+ }
+ }
+ } else {
+ // simply put the value
+ $result[$key] = $value;
+ }
+ }
+ }
+ }
+ return $result;
+}
+
+
+/*
+ * converts a string like "a,b,c,d"
+ * into an array like array("a" => "b", "c" => "d")
+ */
+function explode_assoc($delimiter, $string) {
+ $array = explode($delimiter, $string);
+ $result = array();
+ $numkeys = floor(count($array) / 2);
+ for ($i = 0; $i < $numkeys; $i += 1) {
+ $result[$array[$i * 2]] = $array[$i * 2 + 1];
+ }
+ return $result;
+}
+
+function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
+ global $config, $aliastable;
+
+ /* Bail if there are no routes, but return an array always so callers don't have to check. */
+ if (!is_array($config['staticroutes']['route'])) {
+ return array();
+ }
+
+ $allstaticroutes = array();
+ $allsubnets = array();
+ /* Loop through routes and expand aliases as we find them. */
+ foreach ($config['staticroutes']['route'] as $route) {
+ if (is_alias($route['network'])) {
+ if (!isset($aliastable[$route['network']])) {
+ continue;
+ }
+
+ $subnets = preg_split('/\s+/', $aliastable[$route['network']]);
+ foreach ($subnets as $net) {
+ if (!is_subnet($net)) {
+ if (is_ipaddrv4($net)) {
+ $net .= "/32";
+ } else if (is_ipaddrv6($net)) {
+ $net .= "/128";
+ } else if ($returnhostnames === false || !is_fqdn($net)) {
+ continue;
+ }
+ }
+ $temproute = $route;
+ $temproute['network'] = $net;
+ $allstaticroutes[] = $temproute;
+ $allsubnets[] = $net;
+ }
+ } elseif (is_subnet($route['network'])) {
+ $allstaticroutes[] = $route;
+ $allsubnets[] = $route['network'];
+ }
+ }
+ if ($returnsubnetsonly) {
+ return $allsubnets;
+ } else {
+ return $allstaticroutes;
+ }
+}
+
+/****f* util/get_alias_list
+ * NAME
+ * get_alias_list - Provide a list of aliases.
+ * INPUTS
+ * $type - Optional, can be a string or array specifying what type(s) of aliases you need.
+ * RESULT
+ * Array containing list of aliases.
+ * If $type is unspecified, all aliases are returned.
+ * If $type is a string, all aliases of the type specified in $type are returned.
+ * If $type is an array, all aliases of any type specified in any element of $type are returned.
+ */
+function get_alias_list($type = null) {
+ global $config;
+ $result = array();
+ if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
+ foreach ($config['aliases']['alias'] as $alias) {
+ if ($type === null) {
+ $result[] = $alias['name'];
+ } else if (is_array($type)) {
+ if (in_array($alias['type'], $type)) {
+ $result[] = $alias['name'];
+ }
+ } else if ($type === $alias['type']) {
+ $result[] = $alias['name'];
+ }
+ }
+ }
+ return $result;
+}
+
+/* returns an array consisting of every element of $haystack that is not equal to $needle. */
+function array_exclude($needle, $haystack) {
+ $result = array();
+ if (is_array($haystack)) {
+ foreach ($haystack as $thing) {
+ if ($needle !== $thing) {
+ $result[] = $thing;
+ }
+ }
+ }
+ return $result;
+}
+
+function get_current_theme() {
+ global $config, $g;
+ /*
+ * if user has selected a custom template, use it.
+ * otherwise default to pfsense template
+ */
+ if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"]))) {
+ $theme = $g["default_theme"];
+ } elseif ($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme']))) {
+ $theme = $config['theme'];
+ } else {
+ $theme = "pfsense";
+ }
+ /*
+ * If this device is an apple ipod/iphone
+ * switch the theme to one that works with it.
+ */
+ $lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
+ foreach ($lowres_ua as $useragent) {
+ if (strstr($_SERVER['HTTP_USER_AGENT'], $useragent)) {
+ $theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
+ }
+ }
+ return $theme;
+}
+
+/* Define what is preferred, IPv4 or IPv6 */
+function prefer_ipv4_or_ipv6() {
+ global $config;
+
+ if (isset($config['system']['prefer_ipv4'])) {
+ mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
+ } else {
+ mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
+ }
+}
+
+/* Redirect to page passing parameters via POST */
+function post_redirect($page, $params) {
+ if (!is_array($params)) {
+ return;
+ }
+
+ print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
+ foreach ($params as $key => $value) {
+ print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
+ }
+ print "</form><script type=\"text/javascript\">document.formredir.submit();</script>\n";
+ print "</body></html>\n";
+}
+
+/* Locate disks that can be queried for S.M.A.R.T. data. */
+function get_smart_drive_list() {
+ $disk_list = explode(" ", get_single_sysctl("kern.disks"));
+ foreach ($disk_list as $id => $disk) {
+ // We only want certain kinds of disks for S.M.A.R.T.
+ // 1 is a match, 0 is no match, False is any problem processing the regex
+ if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
+ unset($disk_list[$id]);
+ }
+ }
+ sort($disk_list);
+ return $disk_list;
+}
+
+?>
diff --git a/src/etc/inc/uuid.php b/src/etc/inc/uuid.php
new file mode 100644
index 0000000..700f392
--- /dev/null
+++ b/src/etc/inc/uuid.php
@@ -0,0 +1,327 @@
+<?php
+/*-
+ * Copyright (c) 2008 Fredrik Lindberg - http://www.shapeshifter.se
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * UUID (RFC4122) Generator
+ * http://tools.ietf.org/html/rfc4122
+ *
+ * Implements version 1, 3, 4 and 5
+ */
+class UUID {
+ /* UUID versions */
+ const UUID_TIME = 1; /* Time based UUID */
+ const UUID_NAME_MD5 = 3; /* Name based (MD5) UUID */
+ const UUID_RANDOM = 4; /* Random UUID */
+ const UUID_NAME_SHA1 = 5; /* Name based (SHA1) UUID */
+
+ /* UUID formats */
+ const FMT_FIELD = 100;
+ const FMT_STRING = 101;
+ const FMT_BINARY = 102;
+ const FMT_QWORD = 1; /* Quad-word, 128-bit (not impl.) */
+ const FMT_DWORD = 2; /* Double-word, 64-bit (not impl.) */
+ const FMT_WORD = 4; /* Word, 32-bit (not impl.) */
+ const FMT_SHORT = 8; /* Short (not impl.) */
+ const FMT_BYTE = 16; /* Byte */
+ const FMT_DEFAULT = 16;
+
+ /* Field UUID representation */
+ static private $m_uuid_field = array(
+ 'time_low' => 0, /* 32-bit */
+ 'time_mid' => 0, /* 16-bit */
+ 'time_hi' => 0, /* 16-bit */
+ 'clock_seq_hi' => 0, /* 8-bit */
+ 'clock_seq_low' => 0, /* 8-bit */
+ 'node' => array() /* 48-bit */
+ );
+
+ static private $m_generate = array(
+ self::UUID_TIME => "generateTime",
+ self::UUID_RANDOM => "generateRandom",
+ self::UUID_NAME_MD5 => "generateNameMD5",
+ self::UUID_NAME_SHA1 => "generateNameSHA1"
+ );
+
+ static private $m_convert = array(
+ self::FMT_FIELD => array(
+ self::FMT_BYTE => "conv_field2byte",
+ self::FMT_STRING => "conv_field2string",
+ self::FMT_BINARY => "conv_field2binary"
+ ),
+ self::FMT_BYTE => array(
+ self::FMT_FIELD => "conv_byte2field",
+ self::FMT_STRING => "conv_byte2string",
+ self::FMT_BINARY => "conv_byte2binary"
+ ),
+ self::FMT_STRING => array(
+ self::FMT_BYTE => "conv_string2byte",
+ self::FMT_FIELD => "conv_string2field",
+ self::FMT_BINARY => "conv_string2binary"
+ ),
+ );
+
+ /* Swap byte order of a 32-bit number */
+ static private function swap32($x) {
+ return (($x & 0x000000ff) << 24) | (($x & 0x0000ff00) << 8) |
+ (($x & 0x00ff0000) >> 8) | (($x & 0xff000000) >> 24);
+ }
+
+ /* Swap byte order of a 16-bit number */
+ static private function swap16($x) {
+ return (($x & 0x00ff) << 8) | (($x & 0xff00) >> 8);
+ }
+
+ /* Auto-detect UUID format */
+ static private function detectFormat($src) {
+ if (is_string($src))
+ return self::FMT_STRING;
+ else if (is_array($src)) {
+ $len = count($src);
+ if ($len == 1 || ($len % 2) == 0)
+ return $len;
+ else
+ return (-1);
+ }
+ else
+ return self::FMT_BINARY;
+ }
+
+ /*
+ * Public API, generate a UUID of 'type' in format 'fmt' for
+ * the given namespace 'ns' and node 'node'
+ */
+ static public function generate($type, $fmt = self::FMT_BYTE,
+ $node = "", $ns = "") {
+ $func = self::$m_generate[$type];
+ if (!isset($func))
+ return null;
+ $conv = self::$m_convert[self::FMT_FIELD][$fmt];
+
+ $uuid = self::$func($ns, $node);
+ return self::$conv($uuid);
+ }
+
+ /*
+ * Public API, convert a UUID from one format to another
+ */
+ static public function convert($uuid, $from, $to) {
+ $conv = self::$m_convert[$from][$to];
+ if (!isset($conv))
+ return ($uuid);
+
+ return (self::$conv($uuid));
+ }
+
+ /*
+ * Generate an UUID version 4 (pseudo random)
+ */
+ static private function generateRandom($ns, $node) {
+ $uuid = self::$m_uuid_field;
+
+ $uuid['time_hi'] = (4 << 12) | (mt_rand(0, 0x1000));
+ $uuid['clock_seq_hi'] = (1 << 7) | mt_rand(0, 128);
+ $uuid['time_low'] = mt_rand(0, 0xffffffff);
+ $uuid['time_mid'] = mt_rand(0, 0x0000ffff);
+ $uuid['clock_seq_low'] = mt_rand(0, 255);
+ for ($i = 0; $i < 6; $i++)
+ $uuid['node'][$i] = mt_rand(0, 255);
+ return ($uuid);
+ }
+
+ /*
+ * Generate UUID version 3 and 5 (name based)
+ */
+ static private function generateName($ns, $node, $hash, $version) {
+ $ns_fmt = self::detectFormat($ns);
+ $field = self::convert($ns, $ns_fmt, self::FMT_FIELD);
+
+ /* Swap byte order to keep it in big endian on all platforms */
+ $field['time_low'] = self::swap32($field['time_low']);
+ $field['time_mid'] = self::swap16($field['time_mid']);
+ $field['time_hi'] = self::swap16($field['time_hi']);
+
+ /* Convert the namespace to binary and concatenate node */
+ $raw = self::convert($field, self::FMT_FIELD, self::FMT_BINARY);
+ $raw .= $node;
+
+ /* Hash the namespace and node and convert to a byte array */
+ $val = $hash($raw, true);
+ $tmp = unpack('C16', $val);
+ foreach (array_keys($tmp) as $key)
+ $byte[$key - 1] = $tmp[$key];
+
+ /* Convert byte array to a field array */
+ $field = self::conv_byte2field($byte);
+
+ $field['time_low'] = self::swap32($field['time_low']);
+ $field['time_mid'] = self::swap16($field['time_mid']);
+ $field['time_hi'] = self::swap16($field['time_hi']);
+
+ /* Apply version and constants */
+ $field['clock_seq_hi'] &= 0x3f;
+ $field['clock_seq_hi'] |= (1 << 7);
+ $field['time_hi'] &= 0x0fff;
+ $field['time_hi'] |= ($version << 12);
+
+ return ($field);
+ }
+ static private function generateNameMD5($ns, $node) {
+ return self::generateName($ns, $node, "md5",
+ self::UUID_NAME_MD5);
+ }
+ static private function generateNameSHA1($ns, $node) {
+ return self::generateName($ns, $node, "sha1",
+ self::UUID_NAME_SHA1);
+ }
+
+ /*
+ * Generate UUID version 1 (time based)
+ */
+ static private function generateTime($ns, $node) {
+ $uuid = self::$m_uuid_field;
+
+ /*
+ * Get current time in 100 ns intervals. The magic value
+ * is the offset between UNIX epoch and the UUID UTC
+ * time base October 15, 1582.
+ */
+ $tp = gettimeofday();
+ $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) +
+ 0x01B21DD213814000;
+
+ /* Work around PHP 32-bit bit-operation limits */
+ $q = intval($time / 0xffffffff);
+ $low = $time - ($q * (0xffffffff + 1));
+ $high = intval(($time - $low) / 0xffffffff);
+
+ $uuid['time_low'] = $low;
+ $uuid['time_mid'] = $high & 0x0000ffff;
+ $uuid['time_hi'] = ($high & 0x0fff) | (self::UUID_TIME << 12);
+
+ /*
+ * We don't support saved state information and generate
+ * a random clock sequence each time.
+ */
+ $uuid['clock_seq_hi'] = (1 << 7) | mt_rand(0, 128);
+ $uuid['clock_seq_low'] = mt_rand(0, 255);
+
+ /*
+ * Node should be set to the 48-bit IEEE node identifier, but
+ * we leave it for the user to supply the node.
+ */
+ for ($i = 0; $i < 6; $i++)
+ $uuid['node'][$i] = ord(substr($node, $i, 1));
+
+ return ($uuid);
+ }
+
+ /* Assumes correct byte order */
+ static private function conv_field2byte($src) {
+ $uuid[0] = ($src['time_low'] & 0xff000000) >> 24;
+ $uuid[1] = ($src['time_low'] & 0x00ff0000) >> 16;
+ $uuid[2] = ($src['time_low'] & 0x0000ff00) >> 8;
+ $uuid[3] = ($src['time_low'] & 0x000000ff);
+ $uuid[4] = ($src['time_mid'] & 0xff00) >> 8;
+ $uuid[5] = ($src['time_mid'] & 0x00ff);
+ $uuid[6] = ($src['time_hi'] & 0xff00) >> 8;
+ $uuid[7] = ($src['time_hi'] & 0x00ff);
+ $uuid[8] = $src['clock_seq_hi'];
+ $uuid[9] = $src['clock_seq_low'];
+
+ for ($i = 0; $i < 6; $i++)
+ $uuid[10+$i] = $src['node'][$i];
+
+ return ($uuid);
+ }
+
+ static private function conv_field2string($src) {
+ $str = sprintf(
+ '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
+ ($src['time_low']), ($src['time_mid']), ($src['time_hi']),
+ $src['clock_seq_hi'], $src['clock_seq_low'],
+ $src['node'][0], $src['node'][1], $src['node'][2],
+ $src['node'][3], $src['node'][4], $src['node'][5]);
+ return ($str);
+ }
+
+ static private function conv_field2binary($src) {
+ $byte = self::conv_field2byte($src);
+ return self::conv_byte2binary($byte);
+ }
+
+ static private function conv_byte2field($uuid) {
+ $field = self::$m_uuid_field;
+ $field['time_low'] = ($uuid[0] << 24) | ($uuid[1] << 16) |
+ ($uuid[2] << 8) | $uuid[3];
+ $field['time_mid'] = ($uuid[4] << 8) | $uuid[5];
+ $field['time_hi'] = ($uuid[6] << 8) | $uuid[7];
+ $field['clock_seq_hi'] = $uuid[8];
+ $field['clock_seq_low'] = $uuid[9];
+
+ for ($i = 0; $i < 6; $i++)
+ $field['node'][$i] = $uuid[10+$i];
+ return ($field);
+ }
+
+ static public function conv_byte2string($src) {
+ $field = self::conv_byte2field($src);
+ return self::conv_field2string($field);
+ }
+
+ static private function conv_byte2binary($src) {
+ $raw = pack('C16', $src[0], $src[1], $src[2], $src[3],
+ $src[4], $src[5], $src[6], $src[7], $src[8], $src[9],
+ $src[10], $src[11], $src[12], $src[13], $src[14], $src[15]);
+ return ($raw);
+ }
+
+ static private function conv_string2field($src) {
+ $parts = sscanf($src, '%x-%x-%x-%x-%02x%02x%02x%02x%02x%02x');
+ $field = self::$m_uuid_field;
+ $field['time_low'] = ($parts[0]);
+ $field['time_mid'] = ($parts[1]);
+ $field['time_hi'] = ($parts[2]);
+ $field['clock_seq_hi'] = ($parts[3] & 0xff00) >> 8;
+ $field['clock_seq_low'] = $parts[3] & 0x00ff;
+ for ($i = 0; $i < 6; $i++)
+ $field['node'][$i] = $parts[4+$i];
+
+ return ($field);
+ }
+
+ static private function conv_string2byte($src) {
+ $field = self::conv_string2field($src);
+ return self::conv_field2byte($field);
+ }
+
+ static private function conv_string2binary($src) {
+ $byte = self::conv_string2byte($src);
+ return self::conv_byte2binary($byte);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/src/etc/inc/voucher.inc b/src/etc/inc/voucher.inc
new file mode 100644
index 0000000..7075fa6
--- /dev/null
+++ b/src/etc/inc/voucher.inc
@@ -0,0 +1,785 @@
+<?php
+/*
+ voucher.inc
+ Copyright (C) 2010-2012 Ermal Luçi <eri@pfsense.org>
+ Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
+ Copyright (C) 2007 Marcel Wiget <mwiget@mac.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/local/bin/voucher
+ pfSense_MODULE: captiveportal
+*/
+
+/* include all configuration functions */
+if (!function_exists('captiveportal_syslog')) {
+ require_once("captiveportal.inc");
+}
+
+function xmlrpc_sync_voucher_expire($vouchers, $syncip, $port, $password, $username) {
+ global $g, $config, $cpzone;
+ require_once("xmlrpc.inc");
+
+ $protocol = "http";
+ if (is_array($config['system']) && is_array($config['system']['webgui']) && !empty($config['system']['webgui']['protocol']) &&
+ $config['system']['webgui']['protocol'] == "https") {
+ $protocol = "https";
+ }
+ if ($protocol == "https" || $port == "443") {
+ $url = "https://{$syncip}";
+ } else {
+ $url = "http://{$syncip}";
+ }
+
+ /* Construct code that is run on remote machine */
+ $method = 'pfsense.exec_php';
+ $execcmd = <<<EOF
+ global \$cpzone;
+ require_once('/etc/inc/captiveportal.inc');
+ require_once('/etc/inc/voucher.inc');
+ \$cpzone = "$cpzone";
+ voucher_expire("$vouchers");
+
+EOF;
+
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+
+ log_error("Captive Portal Voucher XMLRPC sync data {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ $resp = $cli->send($msg, "250");
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Communications error occurred", "");
+ return false;
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Error code received", "");
+ return false;
+ } else {
+ log_error("CaptivePortalVoucherSync XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
+ }
+
+ $toreturn = XML_RPC_Decode($resp->value());
+
+ return $toreturn;
+}
+
+function xmlrpc_sync_voucher_disconnect($dbent, $syncip, $port, $password, $username, $term_cause = 1, $stop_time = null) {
+ global $g, $config, $cpzone;
+ require_once("xmlrpc.inc");
+
+ $protocol = "http";
+ if (is_array($config['system']) && is_array($config['system']['webgui']) && !empty($config['system']['webgui']['protocol']) &&
+ $config['system']['webgui']['protocol'] == "https") {
+ $protocol = "https";
+ }
+ if ($protocol == "https" || $port == "443") {
+ $url = "https://{$syncip}";
+ } else {
+ $url = "http://{$syncip}";
+ }
+
+ /* Construct code that is run on remote machine */
+ $dbent_str = serialize($dbent);
+ $tmp_stop_time = (isset($stop_time)) ? $stop_time : "null";
+ $method = 'pfsense.exec_php';
+ $execcmd = <<<EOF
+ global \$cpzone;
+ require_once('/etc/inc/captiveportal.inc');
+ require_once('/etc/inc/voucher.inc');
+ \$cpzone = "$cpzone";
+ \$radiusservers = captiveportal_get_radius_servers();
+ \$dbent = unserialize("$dbent_str");
+ captiveportal_disconnect(\$dbent, \$radiusservers, $term_cause, $tmp_stop_time);
+
+EOF;
+
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+
+ log_error("Captive Portal Voucher XMLRPC sync data {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ $resp = $cli->send($msg, "250");
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Communications error occurred", "");
+ return false;
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Error code received", "");
+ return false;
+ } else {
+ log_error("CaptivePortalVoucherSync XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
+ }
+
+ $toreturn = XML_RPC_Decode($resp->value());
+
+ return $toreturn;
+}
+
+function xmlrpc_sync_used_voucher($voucher_received, $syncip, $port, $password, $username) {
+ global $g, $config, $cpzone;
+ require_once("xmlrpc.inc");
+
+ $protocol = "http";
+ if (is_array($config['system']) && is_array($config['system']['webgui']) && !empty($config['system']['webgui']['protocol']) &&
+ $config['system']['webgui']['protocol'] == "https") {
+ $protocol = "https";
+ }
+ if ($protocol == "https" || $port == "443") {
+ $url = "https://{$syncip}";
+ } else {
+ $url = "http://{$syncip}";
+ }
+
+ /* Construct code that is run on remote machine */
+ $method = 'pfsense.exec_php';
+ $execcmd = <<<EOF
+ global \$cpzone;
+ require_once('/etc/inc/voucher.inc');
+ \$cpzone = "$cpzone";
+ \$timeleft = voucher_auth("$voucher_received");
+ \$toreturn = array();
+ \$toreturn['timeleft'] = \$timeleft;
+ \$toreturn['voucher'] = array();
+ \$toreturn['voucher']['roll'] = \$config['voucher'][\$cpzone]['roll'];
+
+EOF;
+
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+
+ log_error("Captive Portal Voucher XMLRPC sync data {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ $resp = $cli->send($msg, "250");
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Communications error occurred", "");
+ return null; // $timeleft
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting CaptivePortalVoucherSync XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("CaptivePortalVoucherSync", $error, "Error code received", "");
+ return null; // $timeleft
+ } else {
+ log_error("CaptivePortalVoucherSync XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
+ }
+ $toreturn = XML_RPC_Decode($resp->value());
+ if (!is_array($config['voucher'])) {
+ $config['voucher'] = array();
+ }
+
+ if (is_array($toreturn['voucher']) && is_array($toreturn['voucher']['roll'])) {
+ $config['voucher'][$cpzone]['roll'] = $toreturn['voucher']['roll'];
+ write_config("Captive Portal Voucher database synchronized with {$url}");
+ voucher_configure_zone(true);
+ unset($toreturn['voucher']);
+ } else if (!isset($toreturn['timeleft'])) {
+ return null;
+ }
+
+ return $toreturn['timeleft'];
+}
+
+function voucher_expire($voucher_received) {
+ global $g, $config, $cpzone, $cpzoneid;
+
+ // XMLRPC Call over to the master Voucher node
+ if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
+ $syncip = $config['voucher'][$cpzone]['vouchersyncdbip'];
+ $syncport = $config['voucher'][$cpzone]['vouchersyncport'];
+ $syncpass = $config['voucher'][$cpzone]['vouchersyncpass'];
+ $vouchersyncusername = $config['voucher'][$cpzone]['vouchersyncusername'];
+ xmlrpc_sync_voucher_expire($voucher_received, $syncip, $syncport, $syncpass, $vouchersyncusername);
+ }
+
+ $voucherlck = lock("voucher{$cpzone}", LOCK_EX);
+
+ // read rolls into assoc array with rollid as key and minutes as value
+ $tickets_per_roll = array();
+ $minutes_per_roll = array();
+ if (is_array($config['voucher'][$cpzone]['roll'])) {
+ foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
+ $tickets_per_roll[$rollent['number']] = $rollent['count'];
+ $minutes_per_roll[$rollent['number']] = $rollent['minutes'];
+ }
+ }
+
+ // split into an array. Useful for multiple vouchers given
+ $a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
+ $active_dirty = false;
+ $unsetindexes = array();
+
+ // go through all received vouchers, check their valid and extract
+ // Roll# and Ticket# using the external readvoucher binary
+ foreach ($a_vouchers_received as $voucher) {
+ $v = escapeshellarg($voucher);
+ if (strlen($voucher) < 3) {
+ continue; // seems too short to be a voucher!
+ }
+
+ unset($output);
+ $_gb = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v", $output);
+ list($status, $roll, $nr) = explode(" ", $output[0]);
+ if ($status == "OK") {
+ // check if we have this ticket on a registered roll for this ticket
+ if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
+ // voucher is from a registered roll.
+ if (!isset($active_vouchers[$roll])) {
+ $active_vouchers[$roll] = voucher_read_active_db($roll);
+ }
+ // valid voucher. Store roll# and ticket#
+ if (!empty($active_vouchers[$roll][$voucher])) {
+ $active_dirty = true;
+ unset($active_vouchers[$roll][$voucher]);
+ }
+ // check if voucher already marked as used
+ if (!isset($bitstring[$roll])) {
+ $bitstring[$roll] = voucher_read_used_db($roll);
+ }
+ $pos = $nr >> 3; // divide by 8 -> octet
+ $mask = 1 << ($nr % 8);
+ // mark bit for this voucher as used
+ if (!(ord($bitstring[$roll][$pos]) & $mask)) {
+ $bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
+ }
+ captiveportal_syslog("{$voucher} ({$roll}/{$nr}) forced to expire");
+
+ /* Check if this voucher has any active sessions */
+ $cpentry = captiveportal_read_db("WHERE username = '{$voucher}'");
+ if (!empty($cpentry) && !empty($cpentry[0])) {
+ if (empty($cpzoneid) && !empty($config['captiveportal'][$cpzone])) {
+ $cpzoneid = $config['captiveportal'][$cpzone]['zoneid'];
+ }
+ $cpentry = $cpentry[0];
+ captiveportal_disconnect($cpentry, null, 13);
+ captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "FORCLY TERMINATING VOUCHER {$voucher} SESSION");
+ $unsetindexes[] = $cpentry[5];
+ }
+ } else {
+ captiveportal_syslog("$voucher ($roll/$nr): not found on any registered Roll");
+ }
+ } else {
+ // hmm, thats weird ... not what I expected
+ captiveportal_syslog("$voucher invalid: {$output[0]}!!");
+ }
+ }
+
+ // Refresh active DBs
+ if ($active_dirty == true) {
+ foreach ($active_vouchers as $roll => $active) {
+ voucher_write_active_db($roll, $active);
+ }
+ unset($active_vouchers);
+
+ /* Trigger a sync of the vouchers on config */
+ send_event("service sync vouchers");
+ }
+
+ // Write back the used DB's
+ if (is_array($bitstring)) {
+ foreach ($bitstring as $roll => $used) {
+ if (is_array($used)) {
+ foreach ($used as $u) {
+ voucher_write_used_db($roll, base64_encode($u));
+ }
+ } else {
+ voucher_write_used_db($roll, base64_encode($used));
+ }
+ }
+ unset($bitstring);
+ }
+
+ unlock($voucherlck);
+
+ /* Write database */
+ if (!empty($unsetindexes)) {
+ captiveportal_remove_entries($unsetindexes);
+ }
+
+ return true;
+}
+
+/*
+ * Authenticate a voucher and return the remaining time credit in minutes
+ * if $test is set, don't mark the voucher as used nor add it to the list
+ * of active vouchers
+ * If $test is set, simply test the voucher. Don't change anything
+ * but return a more verbose error and result message back
+ */
+function voucher_auth($voucher_received, $test = 0) {
+ global $g, $config, $cpzone, $dbc;
+
+ if (!isset($config['voucher'][$cpzone]['enable'])) {
+ return 0;
+ }
+
+ // XMLRPC Call over to the master Voucher node
+ if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
+ $syncip = $config['voucher'][$cpzone]['vouchersyncdbip'];
+ $syncport = $config['voucher'][$cpzone]['vouchersyncport'];
+ $syncpass = $config['voucher'][$cpzone]['vouchersyncpass'];
+ $vouchersyncusername = $config['voucher'][$cpzone]['vouchersyncusername'];
+ $remote_time_used = xmlrpc_sync_used_voucher($voucher_received, $syncip, $syncport, $syncpass, $vouchersyncusername);
+ }
+
+ $voucherlck = lock("voucher{$cpzone}", LOCK_EX);
+
+ // read rolls into assoc array with rollid as key and minutes as value
+ $tickets_per_roll = array();
+ $minutes_per_roll = array();
+ if (is_array($config['voucher'][$cpzone]['roll'])) {
+ foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
+ $tickets_per_roll[$rollent['number']] = $rollent['count'];
+ $minutes_per_roll[$rollent['number']] = $rollent['minutes'];
+ }
+ }
+
+ // split into an array. Useful for multiple vouchers given
+ $a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
+ $error = 0;
+ $test_result = array(); // used to display for voucher test option in GUI
+ $total_minutes = 0;
+ $first_voucher = "";
+ $first_voucher_roll = 0;
+
+ // go through all received vouchers, check their valid and extract
+ // Roll# and Ticket# using the external readvoucher binary
+ foreach ($a_vouchers_received as $voucher) {
+ $v = escapeshellarg($voucher);
+ if (strlen($voucher) < 3) {
+ $test_result[] = "{$voucher} invalid: Too short!";
+ captiveportal_syslog("{$voucher} invalid: Too short!");
+ $error++;
+ continue; // seems too short to be a voucher!
+ }
+
+ $result = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v");
+ list($status, $roll, $nr) = explode(" ", $result);
+ if ($status == "OK") {
+ if (!$first_voucher) {
+ // store first voucher. Thats the one we give the timecredit
+ $first_voucher = $voucher;
+ $first_voucher_roll = $roll;
+ }
+ // check if we have this ticket on a registered roll for this ticket
+ if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
+ // voucher is from a registered roll.
+ if (!isset($active_vouchers[$roll])) {
+ $active_vouchers[$roll] = voucher_read_active_db($roll);
+ }
+ // valid voucher. Store roll# and ticket#
+ if (!empty($active_vouchers[$roll][$voucher])) {
+ list($timestamp, $minutes) = explode(",", $active_vouchers[$roll][$voucher]);
+ // we have an already active voucher here.
+ $remaining = intval((($timestamp + (60*$minutes)) - time())/60);
+ $test_result[] = sprintf(gettext('%1$s (%2$s/%3$s) active and good for %4$d Minutes'), $voucher, $roll, $nr, $remaining);
+ $total_minutes += $remaining;
+ } else {
+ // voucher not used. Check if ticket Id is on the roll (not too high)
+ // and if the ticket is marked used.
+ // check if voucher already marked as used
+ if (!isset($bitstring[$roll])) {
+ $bitstring[$roll] = voucher_read_used_db($roll);
+ }
+ $pos = $nr >> 3; // divide by 8 -> octet
+ $mask = 1 << ($nr % 8);
+ if (ord($bitstring[$roll][$pos]) & $mask) {
+ $test_result[] = "$voucher ($roll/$nr) already used and expired";
+ captiveportal_syslog("$voucher ($roll/$nr) already used and expired");
+ $total_minutes = -1; // voucher expired
+ $error++;
+ } else {
+ // mark bit for this voucher as used
+ $bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
+ $test_result[] = "$voucher ($roll/$nr) good for {$minutes_per_roll[$roll]} Minutes";
+ $total_minutes += $minutes_per_roll[$roll];
+ }
+ }
+ } else {
+ $test_result[] = "$voucher ($roll/$nr): not found on any registered Roll";
+ captiveportal_syslog("$voucher ($roll/$nr): not found on any registered Roll");
+ }
+ } else {
+ // hmm, thats weird ... not what I expected
+ $test_result[] = "$voucher invalid: $result !!";
+ captiveportal_syslog("$voucher invalid: $result !!");
+ $error++;
+ }
+ }
+
+ // if this was a test call, we're done. Return the result.
+ if ($test) {
+ if ($error) {
+ $test_result[] = gettext("Access denied!");
+ } else {
+ $test_result[] = sprintf(gettext("Access granted for %d Minutes in total."), $total_minutes);
+ }
+ unlock($voucherlck);
+
+ return $test_result;
+ }
+
+ // if we had an error (one of the vouchers is invalid), return 0.
+ // Discussion: we could return the time remaining for good vouchers, but then
+ // the user wouldn't know that he used at least one invalid voucher.
+ if ($error) {
+ unlock($voucherlck);
+ if ($total_minutes > 0) { // probably not needed, but want to make sure
+ $total_minutes = 0; // we only report -1 (expired) or 0 (no access)
+ }
+ return $total_minutes; // well, at least one voucher had errors. Say NO ACCESS
+ }
+
+ // If we did a XMLRPC sync earlier check the timeleft
+ if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
+ if (!is_null($remote_time_used)) {
+ $total_minutes = $remote_time_used;
+ } else if ($remote_time_used < $total_minutes) {
+ $total_minutes -= $remote_time_used;
+ }
+ }
+
+ // All given vouchers were valid and this isn't simply a test.
+ // Write back the used DB's
+ if (is_array($bitstring)) {
+ foreach ($bitstring as $roll => $used) {
+ if (is_array($used)) {
+ foreach ($used as $u) {
+ voucher_write_used_db($roll, base64_encode($u));
+ }
+ } else {
+ voucher_write_used_db($roll, base64_encode($used));
+ }
+ }
+ }
+
+ // Active DB: we only add the first voucher if multiple given
+ // and give that one all the time credit. This allows the user to logout and
+ // log in later using just the first voucher. It also keeps username limited
+ // to one voucher and that voucher shows the correct time credit in 'active vouchers'
+ if (!empty($active_vouchers[$first_voucher_roll][$first_voucher])) {
+ list($timestamp, $minutes) = explode(",", $active_vouchers[$first_voucher_roll][$first_voucher]);
+ } else {
+ $timestamp = time(); // new voucher
+ $minutes = $total_minutes;
+ }
+
+ $active_vouchers[$first_voucher_roll][$first_voucher] = "$timestamp,$minutes";
+ voucher_write_active_db($first_voucher_roll, $active_vouchers[$first_voucher_roll]);
+
+ /* Trigger a sync of the vouchers on config */
+ send_event("service sync vouchers");
+
+ unlock($voucherlck);
+
+ return $total_minutes;
+}
+
+function voucher_configure($sync = false) {
+ global $config, $g, $cpzone;
+
+ if (is_array($config['voucher'])) {
+ foreach ($config['voucher'] as $voucherzone => $vcfg) {
+ if (platform_booting()) {
+ echo gettext("Enabling voucher support... ");
+ }
+ $cpzone = $voucherzone;
+ $error = voucher_configure_zone($sync);
+ if (platform_booting()) {
+ if ($error) {
+ echo "error\n";
+ } else {
+ echo "done\n";
+ }
+ }
+ }
+ }
+}
+
+function voucher_configure_zone($sync = false) {
+ global $config, $g, $cpzone;
+
+ if (!isset($config['voucher'][$cpzone]['enable'])) {
+ return 0;
+ }
+
+ if ($sync == true) {
+ captiveportal_syslog("Writing voucher db from sync data...");
+ }
+
+ $voucherlck = lock("voucher{$cpzone}", LOCK_EX);
+
+ /* write public key used to verify vouchers */
+ $pubkey = base64_decode($config['voucher'][$cpzone]['publickey']);
+ $fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.public", "w");
+ if (!$fd) {
+ captiveportal_syslog("Voucher error: cannot write voucher.public\n");
+ unlock($voucherlck);
+ return 1;
+ }
+ fwrite($fd, $pubkey);
+ fclose($fd);
+ @chmod("{$g['varetc_path']}/voucher_{$cpzone}.public", 0600);
+
+ /* write config file used by voucher binary to decode vouchers */
+ $fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.cfg", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot write voucher.cfg") . "\n");
+ unlock($voucherlck);
+ return 1;
+ }
+ fwrite($fd, "{$config['voucher'][$cpzone]['rollbits']},{$config['voucher'][$cpzone]['ticketbits']},{$config['voucher'][$cpzone]['checksumbits']},{$config['voucher'][$cpzone]['magic']},{$config['voucher'][$cpzone]['charset']}\n");
+ fclose($fd);
+ @chmod("{$g['varetc_path']}/voucher_{$cpzone}.cfg", 0600);
+ unlock($voucherlck);
+
+ if ((platform_booting() || $sync == true) && is_array($config['voucher'][$cpzone]['roll'])) {
+
+ $voucherlck = lock("voucher{$cpzone}", LOCK_EX);
+
+ // create active and used DB per roll on ramdisk from config
+ foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
+
+ $roll = $rollent['number'];
+ voucher_write_used_db($roll, $rollent['used']);
+ $minutes = $rollent['minutes'];
+ $active_vouchers = array();
+ $a_active = &$rollent['active'];
+ if (is_array($a_active)) {
+ foreach ($a_active as $activent) {
+ $voucher = $activent['voucher'];
+ $timestamp = $activent['timestamp'];
+ $minutes = $activent['minutes'];
+ // its tempting to check for expired timestamps, but during
+ // bootup, we most likely don't have the correct time.
+ $active_vouchers[$voucher] = "$timestamp,$minutes";
+ }
+ }
+ voucher_write_active_db($roll, $active_vouchers);
+ }
+
+ unlock($voucherlck);
+ }
+
+ return 0;
+}
+
+/* write bitstring of used vouchers to ramdisk.
+ * Bitstring must already be base64_encoded!
+ */
+function voucher_write_used_db($roll, $vdb) {
+ global $g, $cpzone;
+
+ $fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db", "w");
+ if ($fd) {
+ fwrite($fd, $vdb . "\n");
+ fclose($fd);
+ } else {
+ voucher_log(LOG_ERR, sprintf(gettext('cant write %1$s/voucher_%s_used_%2$s.db'), $g['vardb_path'], $cpzone, $roll));
+ }
+}
+
+/* return assoc array of active vouchers with activation timestamp
+ * voucher is index.
+ */
+function voucher_read_active_db($roll) {
+ global $g, $cpzone;
+
+ $active = array();
+ $dirty = 0;
+ $file = "{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db";
+ if (file_exists($file)) {
+ $fd = fopen($file, "r");
+ if ($fd) {
+ while (!feof($fd)) {
+ $line = trim(fgets($fd));
+ if ($line) {
+ list($voucher, $timestamp, $minutes) = explode(",", $line); // voucher,timestamp
+ if ((($timestamp + (60*$minutes)) - time()) > 0) {
+ $active[$voucher] = "$timestamp,$minutes";
+ } else {
+ $dirty=1;
+ }
+ }
+ }
+ fclose($fd);
+ if ($dirty) { // if we found expired entries, lets save our snapshot
+ voucher_write_active_db($roll, $active);
+
+ /* Trigger a sync of the vouchers on config */
+ send_event("service sync vouchers");
+ }
+ }
+ }
+ return $active;
+}
+
+/* store array of active vouchers back to DB */
+function voucher_write_active_db($roll, $active) {
+ global $g, $cpzone;
+
+ if (!is_array($active)) {
+ return;
+ }
+ $fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db", "w");
+ if ($fd) {
+ foreach ($active as $voucher => $value) {
+ fwrite($fd, "$voucher,$value\n");
+ }
+ fclose($fd);
+ }
+}
+
+/* return how many vouchers are marked used on a roll */
+function voucher_used_count($roll) {
+ global $g, $cpzone;
+
+ $bitstring = voucher_read_used_db($roll);
+ $max = strlen($bitstring) * 8;
+ $used = 0;
+ for ($i = 1; $i <= $max; $i++) {
+ // check if ticket already used or not.
+ $pos = $i >> 3; // divide by 8 -> octet
+ $mask = 1 << ($i % 8); // mask to test bit in octet
+ if (ord($bitstring[$pos]) & $mask) {
+ $used++;
+ }
+ }
+ unset($bitstring);
+
+ return $used;
+}
+
+function voucher_read_used_db($roll) {
+ global $g, $cpzone;
+
+ $vdb = "";
+ $file = "{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db";
+ if (file_exists($file)) {
+ $fd = fopen($file, "r");
+ if ($fd) {
+ $vdb = trim(fgets($fd));
+ fclose($fd);
+ } else {
+ voucher_log(LOG_ERR, sprintf(gettext('cant read %1$s/voucher_%s_used_%2$s.db'), $g['vardb_path'], $cpzone, $roll));
+ }
+ }
+ return base64_decode($vdb);
+}
+
+function voucher_unlink_db($roll) {
+ global $g, $cpzone;
+ @unlink("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db");
+ @unlink("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db");
+}
+
+/* we share the log with captiveportal for now */
+function voucher_log($priority, $message) {
+
+ $message = trim($message);
+ openlog("logportalauth", LOG_PID, LOG_LOCAL4);
+ syslog($priority, sprintf(gettext("Voucher: %s"), $message));
+ closelog();
+}
+
+/* Save active and used voucher DB into XML config and write it to flash
+ * Called during reboot -> system_reboot_cleanup() and every active voucher change
+ */
+function voucher_save_db_to_config() {
+ global $config, $g, $cpzone;
+
+ if (is_array($config['voucher'])) {
+ foreach ($config['voucher'] as $voucherzone => $vcfg) {
+ $cpzone = $voucherzone;
+ voucher_save_db_to_config_zone();
+ }
+ }
+}
+
+function voucher_save_db_to_config_zone() {
+ global $config, $g, $cpzone;
+
+ if (!isset($config['voucher'][$cpzone]['enable'])) {
+ return; // no vouchers or don't want to save DB's
+ }
+
+ if (!is_array($config['voucher'][$cpzone]['roll'])) {
+ return;
+ }
+
+ $voucherlck = lock("voucher{$cpzone}", LOCK_EX);
+
+ // walk all active rolls and save runtime DB's to flash
+ $a_roll = &$config['voucher'][$cpzone]['roll'];
+ while (list($key, $value) = each($a_roll)) {
+ $rollent = &$a_roll[$key];
+ $roll = $rollent['number'];
+ $bitmask = voucher_read_used_db($roll);
+ $rollent['used'] = base64_encode($bitmask);
+ $active_vouchers = voucher_read_active_db($roll);
+ $db = array();
+ $dbi = 1;
+ foreach ($active_vouchers as $voucher => $line) {
+ list($timestamp, $minutes) = explode(",", $line);
+ $activent['voucher'] = $voucher;
+ $activent['timestamp'] = $timestamp;
+ $activent['minutes'] = $minutes;
+ $db["v{$dbi}"] = $activent;
+ $dbi++;
+ }
+ $rollent['active'] = $db;
+ unset($active_vouchers);
+ }
+
+ unlock($voucherlck);
+
+ write_config("Syncing vouchers");
+ return;
+}
+
+?>
diff --git a/src/etc/inc/vpn.inc b/src/etc/inc/vpn.inc
new file mode 100644
index 0000000..2820822
--- /dev/null
+++ b/src/etc/inc/vpn.inc
@@ -0,0 +1,2056 @@
+<?php
+
+/*
+ vpn.inc
+ Copyright (C) 2004 Scott Ullrich
+ Copyright (C) 2008 Shrew Soft Inc
+ Copyright (C) 2008 Ermal Luçi
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES: /sbin/ifconfig
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/ipsec /usr/local/libexec/ipsec/charon /usr/local/libexec/ipsec/starter
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/filterdns /usr/local/sbin/mpd4
+ pfSense_MODULE: vpn
+*/
+
+require_once("ipsec.inc");
+require_once("filter.inc");
+
+function vpn_ipsec_configure_loglevels($forconfig = false) {
+ global $config, $ipsec_loglevels;
+
+ $cfgtext = array();
+ foreach ($ipsec_loglevels as $lkey => $ldescr) {
+ if (!isset($config['ipsec']["ipsec_{$lkey}"]) && !$forconfig) {
+ mwexec("/usr/local/sbin/ipsec stroke loglevel {$lkey} -- -1", false);
+ } else if (is_numeric($config['ipsec']["ipsec_{$lkey}"]) &&
+ intval($config['ipsec']["ipsec_{$lkey}"]) >= 0 && intval($config['ipsec']["ipsec_{$lkey}"]) <= 5) {
+ $forconfig ? $cfgtext[] = "${lkey} " . (intval($config['ipsec']["ipsec_{$lkey}"]) - 1) :
+ mwexec("/usr/local/sbin/ipsec stroke loglevel {$lkey} " . (intval($config['ipsec']["ipsec_{$lkey}"]) - 1) , false);
+ }
+ }
+ if ($forconfig) {
+ return implode(',', $cfgtext);
+ }
+}
+
+/* include all configuration functions */
+function vpn_ipsec_convert_to_modp($index) {
+
+ $convertion = "";
+ switch ($index) {
+ case '1':
+ $convertion = "modp768";
+ break;
+ case '2':
+ $convertion = "modp1024";
+ break;
+ case '5':
+ $convertion = "modp1536";
+ break;
+ case '14':
+ $convertion = "modp2048";
+ break;
+ case '15':
+ $convertion = "modp3072";
+ break;
+ case '16':
+ $convertion = "modp4096";
+ break;
+ case '17':
+ $convertion = "modp6144";
+ break;
+ case '18':
+ $convertion = "modp8192";
+ break;
+ case '19':
+ $convertion = "ecp256";
+ break;
+ case '20':
+ $convertion = "ecp384";
+ break;
+ case '21':
+ $convertion = "ecp521";
+ break;
+ case '28':
+ $convertion = "ecp256bp";
+ break;
+ case '29':
+ $convertion = "ecp384bp";
+ break;
+ case '30':
+ $convertion = "ecp512bp";
+ break;
+ }
+
+ return $convertion;
+}
+
+function vpn_ipsec_configure($restart = false) {
+ global $config, $g, $sa, $sn, $p1_ealgos, $p2_ealgos, $ipsec_idhandling;
+
+ /* get the automatic ping_hosts.sh ready */
+ unlink_if_exists("{$g['vardb_path']}/ipsecpinghosts");
+ touch("{$g['vardb_path']}/ipsecpinghosts");
+
+ /* service may have been enabled, disabled, or otherwise changed in a way requiring rule updates */
+ filter_configure();
+
+ $syscfg = $config['system'];
+ $ipseccfg = $config['ipsec'];
+ if (!isset($ipseccfg['enable'])) {
+ /* try to stop charon */
+ mwexec("/usr/local/sbin/ipsec stop");
+ /* Stop dynamic monitoring */
+ killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
+
+ /* wait for process to die */
+ sleep(2);
+
+ /* disallow IPSEC, it is off */
+ mwexec("/sbin/ifconfig enc0 down");
+ set_single_sysctl("net.inet.ip.ipsec_in_use", "0");
+
+ return 0;
+ }
+
+ $a_phase1 = $config['ipsec']['phase1'];
+ $a_phase2 = $config['ipsec']['phase2'];
+ $a_client = $config['ipsec']['client'];
+
+ $certpath = "{$g['varetc_path']}/ipsec/ipsec.d/certs";
+ $capath = "{$g['varetc_path']}/ipsec/ipsec.d/cacerts";
+ $keypath = "{$g['varetc_path']}/ipsec/ipsec.d/private";
+ $crlpath = "{$g['varetc_path']}/ipsec/ipsec.d/crls";
+
+ mwexec("/sbin/ifconfig enc0 up");
+ set_single_sysctl("net.inet.ip.ipsec_in_use", "1");
+ if (php_uname('m') != "amd64") {
+ set_single_sysctl("net.inet.ipsec.directdispatch", "0");
+ }
+
+ /* needed for config files */
+ if (!is_dir("{$g['varetc_path']}/ipsec")) {
+ mkdir("{$g['varetc_path']}/ipsec");
+ }
+ if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d")) {
+ mkdir("{$g['varetc_path']}/ipsec/ipsec.d");
+ }
+ if (!is_dir($capath)) {
+ mkdir($capath);
+ }
+ if (!is_dir($keypath)) {
+ mkdir($keypath);
+ }
+ if (!is_dir($crlpath)) {
+ mkdir($crlpath);
+ }
+ if (!is_dir($certpath)) {
+ mkdir($certpath);
+ }
+ if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/aacerts")) {
+ mkdir("{$g['varetc_path']}/ipsec/ipsec.d/aacerts");
+ }
+ if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/acerts")) {
+ mkdir("{$g['varetc_path']}/ipsec/ipsec.d/acerts");
+ }
+ if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/ocspcerts")) {
+ mkdir("{$g['varetc_path']}/ipsec/ipsec.d/ocspcerts");
+ }
+ if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/reqs")) {
+ mkdir("{$g['varetc_path']}/ipsec/ipsec.d/reqs");
+ }
+
+
+ if (platform_booting()) {
+ echo gettext("Configuring IPsec VPN... ");
+ }
+
+ /* fastforwarding is not compatible with ipsec tunnels */
+ set_single_sysctl("net.inet.ip.fastforwarding", "0");
+
+ /* resolve all local, peer addresses and setup pings */
+ $ipmap = array();
+ $rgmap = array();
+ $filterdns_list = array();
+ $listeniflist = array();
+ $aggressive_mode_psk = false;
+ unset($iflist);
+ $ifacesuse = array();
+ if (is_array($a_phase1) && count($a_phase1)) {
+
+ $ipsecpinghosts = "";
+ /* step through each phase1 entry */
+ foreach ($a_phase1 as $ph1ent) {
+ if (isset($ph1ent['disabled'])) {
+ continue;
+ }
+
+ if (strpos($ph1ent['interface'], '_vip')) {
+ $vpninterface = explode('_vip', $ph1ent['interface']);
+ $ifacesuse[] = get_real_interface($vpninterface[0]);
+ } else {
+ $vpninterface = get_failover_interface($ph1ent['interface']);
+ if (strpos($vpninterface, '_vip')) {
+ $vpninterface = explode('_vip', $vpninterface);
+ $ifacesuse[] = get_real_interface($vpninterface[0]);
+ } elseif (!empty($vpninterface)) {
+ $ifacesuse[] = $vpninterface;
+ }
+ }
+
+ if ($ph1ent['mode'] == "aggressive" && ($ph1ent['authentication_method'] == "pre_shared_key" || $ph1ent['authentication_method'] == "xauth_psk_server")) {
+ $aggressive_mode_psk = true;
+ }
+
+ $ikeid = $ph1ent['ikeid'];
+ $listeniflist = get_real_interface($a_phase1['interface']);
+
+ $ep = ipsec_get_phase1_src($ph1ent);
+ if (!is_ipaddr($ep)) {
+ log_error("IPsec ERROR: Could not find phase 1 source for connection {$ph1ent['descr']}. Omitting from configuration file.");
+ continue;
+ }
+
+ if (!in_array($ep, $ipmap)) {
+ $ipmap[] = $ep;
+ }
+
+ /* see if this tunnel has a hostname for the remote-gateway. If so,
+ try to resolve it now and add it to the list for filterdns */
+
+ if (isset ($ph1ent['mobile'])) {
+ continue;
+ }
+
+ $rg = $ph1ent['remote-gateway'];
+
+ if (!is_ipaddr($rg)) {
+ $filterdns_list[] = "{$rg}";
+ add_hostname_to_watch($rg);
+ if (!platform_booting()) {
+ $rg = resolve_retry($rg);
+ }
+ if (!is_ipaddr($rg)) {
+ continue;
+ }
+ }
+ if (array_search($rg, $rgmap)) {
+ log_error("The remote gateway {$rg} already exists on another phase 1 entry");
+ continue;
+ }
+ $rgmap[$ph1ent['remote-gateway']] = $rg;
+
+ if (is_array($a_phase2)) {
+ /* step through each phase2 entry */
+ foreach ($a_phase2 as $ph2ent) {
+ if (isset($ph2ent['disabled'])) {
+ continue;
+ }
+
+ if ($ikeid != $ph2ent['ikeid']) {
+ continue;
+ }
+
+ /* add an ipsec pinghosts entry */
+ if ($ph2ent['pinghost']) {
+ if (!is_array($iflist)) {
+ $iflist = get_configured_interface_list();
+ }
+ $srcip = null;
+ $local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']);
+ if (is_ipaddrv6($ph2ent['pinghost'])) {
+ foreach ($iflist as $ifent => $ifname) {
+ $interface_ip = get_interface_ipv6($ifent);
+ if (!is_ipaddrv6($interface_ip)) {
+ continue;
+ }
+ if (ip_in_subnet($interface_ip, $local_subnet)) {
+ $srcip = $interface_ip;
+ break;
+ }
+ }
+ } else {
+ foreach ($iflist as $ifent => $ifname) {
+ $interface_ip = get_interface_ip($ifent);
+ if (!is_ipaddrv4($interface_ip)) {
+ continue;
+ }
+ if ($local_subnet == "0.0.0.0/0" || ip_in_subnet($interface_ip, $local_subnet)) {
+ $srcip = $interface_ip;
+ break;
+ }
+ }
+ }
+ /* if no valid src IP was found in configured interfaces, try the vips */
+ if (is_null($srcip)) {
+ $viplist = get_configured_vips_list();
+ foreach ($viplist as $vip) {
+ if (ip_in_subnet($vip['ipaddr'], $local_subnet)) {
+ $srcip = $vip['ipaddr'];
+ break;
+ }
+ }
+ }
+ $dstip = $ph2ent['pinghost'];
+ if (is_ipaddrv6($dstip)) {
+ $family = "inet6";
+ } else {
+ $family = "inet";
+ }
+ if (is_ipaddr($srcip)) {
+ $ipsecpinghosts[] = "{$srcip}|{$dstip}|3|||||{$family}|\n";
+ }
+ }
+ }
+ }
+ }
+ @file_put_contents("{$g['vardb_path']}/ipsecpinghosts", $ipsecpinghosts);
+ unset($ipsecpinghosts);
+ }
+ unset($iflist);
+
+ $accept_unencrypted = "";
+ if (isset($config['ipsec']['acceptunencryptedmainmode'])) {
+ $accept_unencrypted = "accept_unencrypted_mainmode_messages = yes";
+ }
+
+ $stronconf = '';
+ if (file_exists("{$g['varetc_path']}/ipsec/strongswan.conf")) {
+ $stronconf = file_get_contents("{$g['varetc_path']}/ipsec/strongswan.conf");
+ }
+
+ $i_dont_care_about_security_and_use_aggressive_mode_psk = "";
+ if ($aggressive_mode_psk) {
+ log_error("WARNING: Setting i_dont_care_about_security_and_use_aggressive_mode_psk option because a phase 1 is configured using aggressive mode with pre-shared keys. This is not a secure configuration.");
+ if (!empty($stronconf) && strpos($stronconf, 'i_dont_care_about_security_and_use_aggressive_mode_psk') === FALSE) {
+ $restart = true;
+ }
+ $i_dont_care_about_security_and_use_aggressive_mode_psk = "i_dont_care_about_security_and_use_aggressive_mode_psk=yes";
+ }
+
+ $unity_enabled = 'yes';
+ if (isset($config['ipsec']['unityplugin'])) {
+ $unity_enabled = 'no';
+ if (file_exists("/usr/local/lib/ipsec/plugins/libstrongswan-unity.so")) {
+ conf_mount_rw();
+ mwexec("mv /usr/local/lib/ipsec/plugins/libstrongswan-unity.so /usr/local/lib/ipsec/plugins/libstrongswan-unity.MOVED");
+ conf_mount_ro();
+ }
+ } else if (file_exists("/usr/local/lib/ipsec/plugins/libstrongswan-unity.MOVED")) {
+ conf_mount_rw();
+ mwexec("mv /usr/local/lib/ipsec/plugins/libstrongswan-unity.MOVED /usr/local/lib/ipsec/plugins/libstrongswan-unity.so");
+ conf_mount_ro();
+ }
+
+ $makebeforebreak = '';
+ if (isset($config['ipsec']['makebeforebreak'])) {
+ $makebeforebreak = 'make_before_break = yes';
+ }
+
+ if (isset($config['ipsec']['enableinterfacesuse'])) {
+ if (!empty($ifacesuse)) {
+ $ifacesuse = 'interfaces_use = ' . implode(',', array_unique($ifacesuse));
+ } else {
+ $ifacesuse = '';
+ }
+ } else {
+ $ifacesuse = '';
+ }
+
+ unset($stronconf);
+
+ $strongswan = <<<EOD
+
+# Automatically generated config file - DO NOT MODIFY. Changes will be overwritten.
+starter {
+load_warning = no
+}
+
+charon {
+# number of worker threads in charon
+threads = 16
+ikesa_table_size = 32
+ikesa_table_segments = 4
+init_limit_half_open = 1000
+install_routes = no
+{$i_dont_care_about_security_and_use_aggressive_mode_psk}
+{$accept_unencrypted}
+cisco_unity = {$unity_enabled}
+{$ifacesuse}
+{$makebeforebreak}
+
+# And two loggers using syslog. The subsections define the facility to log
+# to, currently one of: daemon, auth.
+syslog {
+ identifier = charon
+ # default level to the LOG_DAEMON facility
+ daemon {
+ ike_name = yes
+ }
+ # very minimalistic IKE auditing logs to LOG_AUTHPRIV
+ auth {
+ default = -1
+ ike = 1
+ ike_name = yes
+ }
+}
+
+EOD;
+
+ $strongswan .= "\tplugins {\n";
+
+ $a_servers = auth_get_authserver_list();
+ foreach ($a_servers as $id => $pconfig) {
+ if ($id == $config['ipsec']['client']['user_source'] && $pconfig['type'] == "radius") {
+ $strongswan .= <<<EOD
+ eap-radius {
+ class_group = yes
+ eap_start = no
+ servers {
+ primary {
+ address = {$pconfig['host']}
+ secret = {$pconfig['radius_secret']}
+ auth_port = {$pconfig['radius_auth_port']}
+ acct_port = {$pconfig['radius_acct_port']}
+ }
+ }
+ }
+
+EOD;
+ break;
+ }
+ }
+
+ if (is_array($a_client) && isset($a_client['enable'])) {
+ $strongswan .= "\t\tattr {\n";
+ if ($a_client['pool_address'] && $a_client['pool_netbits']) {
+ $strongswan .= "\t\t\tsubnet = {$a_client['pool_address']}/{$a_client['pool_netbits']}\n";
+ }
+
+ $cfgservers = array();
+ if (!empty($a_client['dns_server1'])) {
+ $cfgservers[] = $a_client['dns_server1'];
+ }
+ if (!empty($a_client['dns_server2'])) {
+ $cfgservers[] = $a_client['dns_server2'];
+ }
+ if (!empty($a_client['dns_server3'])) {
+ $cfgservers[] = $a_client['dns_server3'];
+ }
+ if (!empty($a_client['dns_server4'])) {
+ $cfgservers[] = $a_client['dns_server4'];
+ }
+
+ if (!empty($cfgservers)) {
+ $strongswan .= "\t\t\tdns = " . implode(",", $cfgservers) . "\n";
+ }
+ unset($cfgservers);
+ $cfgservers = array();
+ if (!empty($a_client['wins_server1'])) {
+ $cfgservers[] = $a_client['wins_server1'];
+ }
+ if (!empty($a_client['wins_server2'])) {
+ $cfgservers[] = $a_client['wins_server2'];
+ }
+ if (!empty($cfgservers)) {
+ $strongswan .= "\t\t\tnbns = " . implode(",", $cfgservers) . "\n";
+ }
+ unset($cfgservers);
+
+ if (isset($a_client['net_list']) && is_array($a_phase2)) {
+ $net_list = '';
+ foreach ($a_phase2 as $ph2ent) {
+ if (isset($ph2ent['disabled'])) {
+ continue;
+ }
+
+ if (!isset($ph2ent['mobile'])) {
+ continue;
+ }
+
+ $localid = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']);
+
+ if (!empty($net_list)) {
+ $net_list .= ",";
+ }
+ $net_list .= $localid;
+ }
+
+ if (!empty($net_list)) {
+ $strongswan .= "\t\t\tsplit-include = {$net_list}\n";
+ unset($net_list);
+ }
+ }
+
+ if (!empty($a_client['dns_domain'])) {
+ $strongswan .= "\t\t\t# Search domain and default domain\n";
+ $strongswan .= "\t\t\t28674 = \"{$a_client['dns_domain']}\"\n";
+ if (empty($a_client['dns_split'])) {
+ $strongswan .= "\t\t\t28675 = \"{$a_client['dns_domain']}\"";
+ }
+ $strongswan .= "\n";
+ }
+
+ if (!empty($a_client['dns_split'])) {
+ $strongswan .= "\t\t\t28675 = {$a_client['dns_split']}\n";
+ }
+
+ if (!empty($a_client['login_banner'])) {
+ $strongswan .= "\t\t\t28672 = \"{$a_client['login_banner']}\"\n";
+ }
+
+ if (isset($a_client['save_passwd'])) {
+ $strongswan .= "\t\t\t28673 = 1\n";
+ }
+
+ if ($a_client['pfs_group']) {
+ $strongswan .= "\t\t\t28679 = \"{$a_client['pfs_group']}\"\n";
+ }
+ $strongswan .= "\t\t}\n";
+
+ if ($a_client['user_source'] != "none") {
+ $strongswan .= "\t\txauth-generic {\n";
+ $strongswan .= "\t\t\tscript = /etc/inc/ipsec.auth-user.php\n";
+ $strongswan .= "\t\t\tauthcfg = ";
+ $firstsed = 0;
+ $authcfgs = explode(",", $a_client['user_source']);
+ foreach ($authcfgs as $authcfg) {
+ if ($firstsed > 0) {
+ $strongswan .= ",";
+ }
+ if ($authcfg == "system") {
+ $authcfg = "Local Database";
+ }
+ $strongswan .= $authcfg;
+ $firstsed = 1;
+ }
+ $strongswan .= "\n";
+ $strongswan .= "\t\t}\n";
+ }
+ }
+
+ $strongswan .= "\t}\n}\n";
+ @file_put_contents("{$g['varetc_path']}/ipsec/strongswan.conf", $strongswan);
+ unset($strongswan);
+
+ /* generate CA certificates files */
+ if (is_array($config['ca']) && count($config['ca'])) {
+ foreach ($config['ca'] as $ca) {
+ if (!isset($ca['crt'])) {
+ log_error(sprintf(gettext("Error: Invalid certificate info for %s"), $ca['descr']));
+ continue;
+ }
+ $cert = base64_decode($ca['crt']);
+ $x509cert = openssl_x509_parse(openssl_x509_read($cert));
+ if (!is_array($x509cert) || !isset($x509cert['hash'])) {
+ log_error(sprintf(gettext("Error: Invalid certificate hash info for %s"), $ca['descr']));
+ continue;
+ }
+ $fname = "{$capath}/{$x509cert['hash']}.0.crt";
+ if (!@file_put_contents($fname, $cert)) {
+ log_error(sprintf(gettext("Error: Cannot write IPsec CA file for %s"), $ca['descr']));
+ continue;
+ }
+ unset($cert);
+ }
+ }
+
+ /* write out CRL files */
+ if (is_array($config['crl']) && count($config['crl'])) {
+ foreach ($config['crl'] as $crl) {
+ if (!isset($crl['text'])) {
+ log_error(sprintf(gettext("Warning: Missing CRL data for %s"), $crl['descr']));
+ continue;
+ }
+ $fpath = "{$crlpath}/{$crl['refid']}.crl";
+ if (!@file_put_contents($fpath, base64_decode($crl['text']))) {
+ log_error(sprintf(gettext("Error: Cannot write IPsec CRL file for %s"), $crl['descr']));
+ continue;
+ }
+ }
+ }
+
+ $pskconf = "";
+
+ if (is_array($a_phase1) && count($a_phase1)) {
+ foreach ($a_phase1 as $ph1ent) {
+
+ if (isset($ph1ent['disabled'])) {
+ continue;
+ }
+
+ if (strstr($ph1ent['authentication_method'], 'rsa') ||
+ in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius'))) {
+ $certline = '';
+
+ $ikeid = $ph1ent['ikeid'];
+ $cert = lookup_cert($ph1ent['certref']);
+
+ if (!$cert) {
+ log_error(sprintf(gettext("Error: Invalid phase1 certificate reference for %s"), $ph1ent['name']));
+ continue;
+ }
+
+ @chmod($certpath, 0600);
+
+ $ph1keyfile = "{$keypath}/cert-{$ikeid}.key";
+ if (!file_put_contents($ph1keyfile, base64_decode($cert['prv']))) {
+ log_error(sprintf(gettext("Error: Cannot write phase1 key file for %s"), $ph1ent['name']));
+ continue;
+ }
+ @chmod($ph1keyfile, 0600);
+
+ $ph1certfile = "{$certpath}/cert-{$ikeid}.crt";
+ if (!file_put_contents($ph1certfile, base64_decode($cert['crt']))) {
+ log_error(sprintf(gettext("Error: Cannot write phase1 certificate file for %s"), $ph1ent['name']));
+ @unlink($ph1keyfile);
+ continue;
+ }
+ @chmod($ph1certfile, 0600);
+
+ /* XXX" Traffic selectors? */
+ $pskconf .= " : RSA {$ph1keyfile}\n";
+ } else {
+ list ($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
+ list ($peerid_type, $peerid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
+
+ $myid = trim($myid_data);
+
+ if (empty($peerid_data)) {
+ continue;
+ }
+
+ if ($myid_type == 'fqdn' && !empty($myid)) {
+ $myid = "@{$myid}";
+ }
+
+ $myid = isset($ph1ent['mobile']) ? trim($myid_data) : "%any";
+
+ $peerid = ($peerid_data != 'allusers') ? trim($peerid_data) : '';
+
+ if ($peerid_type == 'fqdn' && !empty($peerid)) {
+ $peerid = "@{$peerid}";
+ }
+
+ if (!empty($ph1ent['pre-shared-key'])) {
+ $pskconf .= "{$myid} {$peerid} : PSK 0s" . base64_encode(trim($ph1ent['pre-shared-key'])) . "\n";
+ }
+ }
+ }
+ }
+
+ /* Add user PSKs */
+ if (is_array($config['system']) && is_array($config['system']['user'])) {
+ foreach ($config['system']['user'] as $user) {
+ if (!empty($user['ipsecpsk'])) {
+ $pskconf .= "{$myid} {$user['name']} : PSK 0s" . base64_encode($user['ipsecpsk']) . "\n";
+ }
+ }
+ unset($user);
+ }
+
+ /* add PSKs for mobile clients */
+ if (is_array($ipseccfg['mobilekey'])) {
+ foreach ($ipseccfg['mobilekey'] as $key) {
+ if ($key['ident'] == "allusers") {
+ $key['ident'] = '%any';
+ }
+ if (empty($key['type'])) {
+ $key['type'] = 'PSK';
+ }
+ $pskconf .= "{$myid} {$key['ident']} : {$key['type']} 0s" . base64_encode($key['pre-shared-key']) . "\n";
+ }
+ unset($key);
+ }
+
+ @file_put_contents("{$g['varetc_path']}/ipsec/ipsec.secrets", $pskconf);
+ chmod("{$g['varetc_path']}/ipsec/ipsec.secrets", 0600);
+ unset($pskconf);
+
+ $uniqueids = 'yes';
+ if (!empty($config['ipsec']['uniqueids'])) {
+ if (array_key_exists($config['ipsec']['uniqueids'], $ipsec_idhandling)) {
+ $uniqueids = $config['ipsec']['uniqueids'];
+ }
+ }
+ $natfilterrules = false;
+ /* begin ipsec.conf */
+ $ipsecconf = "";
+ $enablecompression = false;
+ if (is_array($a_phase1) && count($a_phase1)) {
+
+ $ipsecconf .= "# This file is automatically generated. Do not edit\n";
+ $ipsecconf .= "config setup\n\tuniqueids = {$uniqueids}\n";
+ $ipsecconf .= "\tcharondebug=\"" . vpn_ipsec_configure_loglevels(true) . "\"\n";
+
+ if (isset($config['ipsec']['strictcrlpolicy'])) {
+ $ipsecconf .= "\tstrictcrlpolicy = yes \n";
+ }
+
+ if (!isset($config['ipsec']['noshuntlaninterfaces'])) {
+ if ($config['interfaces']['lan']) {
+ $lanip = get_interface_ip("lan");
+ if (!empty($lanip) && is_ipaddrv4($lanip)) {
+ $lansn = get_interface_subnet("lan");
+ $lansa = gen_subnet($lanip, $lansn);
+ $ipsecconf .= <<<EOD
+
+conn bypasslan
+ leftsubnet = {$lansa}/{$lansn}
+ rightsubnet = {$lansa}/{$lansn}
+ authby = never
+ type = passthrough
+ auto = route
+
+EOD;
+ }
+ }
+ }
+
+ foreach ($a_phase1 as $ph1ent) {
+ if (isset($ph1ent['disabled'])) {
+ continue;
+ }
+
+ if ($ph1ent['mode'] == "aggressive") {
+ $aggressive = "yes";
+ } else {
+ $aggressive = "no";
+ }
+
+ $ep = ipsec_get_phase1_src($ph1ent);
+ if (!$ep) {
+ continue;
+ }
+
+ $ikeid = $ph1ent['ikeid'];
+ $keyexchange = "ikev1";
+ $passive = "route";
+ if (!empty($ph1ent['iketype'])) {
+ if ($ph1ent['iketype'] == "ikev2") {
+ $keyexchange = "ikev2";
+ //$passive = "start";
+ }
+ }
+
+ if (isset($ph1ent['mobile'])) {
+ $right_spec = "%any";
+ $passive = 'add';
+ } else {
+ if (isset($ph1ent['responderonly'])) {
+ $passive = 'add';
+ }
+
+ $right_spec = $ph1ent['remote-gateway'];
+ if (is_ipaddr($right_spec)) {
+ $sourcehost = $right_spec;
+ } else {
+ $sourcehost = $rgmap['remote-gateway'];
+ }
+
+ if ($ph1ent['protocol'] == 'inet') {
+ if (strpos($ph1ent['interface'], '_vip')) {
+ $vpninterface = explode('_vip', $ph1ent['interface']);
+ $ifacesuse = get_real_interface($vpninterface[0]);
+ $vpninterface = $vpninterface[0];
+ } else {
+ $ifacesuse = get_failover_interface($ph1ent['interface']);
+ if (strpos($ifacesuse, '_vip')) {
+ $vpninterface = explode('_vip', $ifacesuse);
+ $ifacesuse = get_real_interface($vpninterface[0]);
+ $vpninterface = $vpninterface[0];
+ } else {
+ $vpninterface = convert_real_interface_to_friendly_interface_name($ifacesuse);
+ }
+ }
+
+ if (!empty($ifacesuse) && interface_has_gateway($vpninterface)) {
+ $gatewayip = get_interface_gateway($vpninterface);
+ $interfaceip = get_interface_ip($vpninterface);
+ $subnet_bits = get_interface_subnet($vpninterface);
+ $subnet_ip = gen_subnetv4($interfaceip, $subnet_bits);
+ /* if the remote gateway is in the local subnet, then don't add a route */
+ if (!ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}")) {
+ if (is_ipaddrv4($gatewayip)) {
+ // log_error("IPSEC interface is not WAN but {$ifacesuse}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
+ mwexec("/sbin/route change -host {$sourcehost} {$gatewayip}", true);
+ }
+ }
+ }
+ } else if ($ph1ent['protocol'] == 'inet6') {
+ if (strpos($ph1ent['interface'], '_vip')) {
+ $vpninterface = explode('_vip', $ph1ent['interface']);
+ $ifacesuse = get_real_interface($vpninterface[0]);
+ $vpninterface = $vpninterface[0];
+ } else {
+ $ifacesuse = get_failover_interface($ph1ent['interface']);
+ if (strpos($ifacesuse, '_vip')) {
+ $vpninterface = explode('_vip', $ifacesuse);
+ $ifacesuse = get_real_interface($vpninterface[0]);
+ $vpninterface = $vpninterface[0];
+ } else {
+ $vpninterface = convert_real_interface_to_friendly_interface_name($ifacesuse);
+ }
+ }
+
+ if (!empty($ifacesuse) && interface_has_gateway($vpninterface)) {
+ $gatewayip = get_interface_gateway_v6($vpninterface);
+ $interfaceip = get_interface_ipv6($vpninterface);
+ $subnet_bits = get_interface_subnetv6($vpninterface);
+ $subnet_ip = gen_subnetv6($interfaceip, $subnet_bits);
+ /* if the remote gateway is in the local subnet, then don't add a route */
+ if (!ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}")) {
+ if (is_ipaddrv6($gatewayip)) {
+ // log_error("IPSEC interface is not WAN but {$ifacesuse}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
+ mwexec("/sbin/route change -inet6 -host {$sourcehost} {$gatewayip}", true);
+ }
+ }
+ }
+ }
+ }
+
+ list ($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
+ if ($myid_type != 'address' && $myid_type != 'keyid' && $myid_type != 'asn1dn') {
+ $myid_data = "{$myid_type}:{$myid_data}";
+ } elseif ($myid_type == "asn1dn" && !empty($myid_data)) {
+ if ($myid_data[0] == '#') {
+ /* asn1dn needs double quotes */
+ $myid_data = "\"{$myid_type}:{$myid_data}\"";
+ } else {
+ $myid_data = "\"{$myid_data}\"";
+ }
+ }
+ $leftid = '';
+ if (!empty($myid_data)) {
+ $leftid = "leftid = {$myid_data}";
+ }
+
+ $peerid_spec = '';
+ if (isset($ph1ent['mobile']) && ($ph1ent['authentication_method'] == "pre_shared_key" || $ph1ent['authentication_method'] == "xauth_psk_server")) {
+ // Only specify peer ID if we are not dealing with mobile PSK
+ } else {
+ list ($peerid_type, $peerid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
+ if ($peerid_type == 'any') {
+ $peerid_spec = '';
+ } elseif ($peerid_type != 'address' && $peerid_type != 'keyid' && $peerid_type != 'asn1dn') {
+ $peerid_spec = "{$peerid_type}:{$peerid_data}";
+ } elseif ($peerid_type == "asn1dn") {
+ /* asn1dn needs double quotes */
+ if ($peerid_data[0] == '#') {
+ $peerid_spec = "\"{$peerid_type}:{$peerid_data}\"";
+ } elseif (!empty($peerid_data)) {
+ $peerid_spec = "\"{$peerid_data}\"";
+ }
+ } else {
+ $peerid_spec = $peerid_data;
+ }
+ }
+
+ if (is_array($ph1ent['encryption-algorithm']) && !empty($ph1ent['encryption-algorithm']['name']) && !empty($ph1ent['hash-algorithm'])) {
+ $ealgosp1 = '';
+ $ealg_id = $ph1ent['encryption-algorithm']['name'];
+ $ealg_kl = $ph1ent['encryption-algorithm']['keylen'];
+ if ($ealg_kl) {
+ $ealgosp1 = "ike = {$ealg_id}{$ealg_kl}-{$ph1ent['hash-algorithm']}";
+ } else {
+ $ealgosp1 = "ike = {$ealg_id}-{$ph1ent['hash-algorithm']}";
+ }
+
+ $modp = vpn_ipsec_convert_to_modp($ph1ent['dhgroup']);
+ if (!empty($modp)) {
+ $ealgosp1 .= "-{$modp}";
+ }
+
+ $ealgosp1 .= "!";
+ }
+
+ if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) {
+ if ($passive == "route") {
+ $dpdline = "dpdaction = restart";
+ } else {
+ $dpdline = "dpdaction = clear";
+ }
+ $dpdline .= "\n\tdpddelay = {$ph1ent['dpd_delay']}s";
+ $dpdtimeout = $ph1ent['dpd_delay'] * ($ph1ent['dpd_maxfail'] + 1);
+ $dpdline .= "\n\tdpdtimeout = {$dpdtimeout}s";
+ } else {
+ $dpdline = "dpdaction = none";
+ }
+
+ $ikelifeline = '';
+ if ($ph1ent['lifetime']) {
+ $ikelifeline = "ikelifetime = {$ph1ent['lifetime']}s";
+ }
+
+ $rightsourceip = NULL;
+ if (isset($ph1ent['mobile']) && !empty($a_client['pool_address'])) {
+ $rightsourceip = "\trightsourceip = {$a_client['pool_address']}/{$a_client['pool_netbits']}\n";
+ }
+
+ $authentication = "";
+ switch ($ph1ent['authentication_method']) {
+ case 'eap-mschapv2':
+ if (isset($ph1ent['mobile'])) {
+ $authentication = "eap_identity=%any\n\t";
+ $authentication .= "leftauth=pubkey\n\trightauth=eap-mschapv2";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ }
+ break;
+ case 'eap-tls':
+ if (isset($ph1ent['mobile'])) {
+ $authentication = "eap_identity=%identity\n\t";
+ $authentication .= "leftauth=pubkey\n\trightauth=eap-tls";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ } else {
+ $authentication = "leftauth=eap-tls\n\trightauth=eap-tls";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ }
+ break;
+ case 'eap-radius':
+ if (isset($ph1ent['mobile'])) {
+ $authentication = "eap_identity=%identity\n\t";
+ $authentication .= "leftauth=pubkey\n\trightauth=eap-radius";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ } else {
+ $authentication = "leftauth=eap-radius\n\trightauth=eap-radius";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ }
+ break;
+ case 'xauth_rsa_server':
+ $authentication = "leftauth = pubkey\n\trightauth = pubkey";
+ $authentication .= "\n\trightauth2 = xauth-generic";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ break;
+ case 'xauth_psk_server':
+ $authentication = "leftauth = psk\n\trightauth = psk";
+ $authentication .= "\n\trightauth2 = xauth-generic";
+ break;
+ case 'pre_shared_key':
+ $authentication = "leftauth = psk\n\trightauth = psk";
+ break;
+ case 'rsasig':
+ $authentication = "leftauth = pubkey\n\trightauth = pubkey";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ break;
+ case 'hybrid_rsa_server':
+ $authentication = "leftauth = xauth-generic\n\trightauth = pubkey";
+ $authentication .= "\n\trightauth2 = xauth";
+ if (!empty($ph1ent['certref'])) {
+ $authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ }
+ break;
+ }
+
+ $left_spec = $ep;
+
+ if (isset($ph1ent['reauth_enable'])) {
+ $reauth = "reauth = no";
+ } else {
+ $reauth = "reauth = yes";
+ }
+ if (isset($ph1ent['rekey_enable'])) {
+ $rekey = "rekey = no";
+ } else {
+ $rekey = "rekey = yes";
+ }
+
+ if ($ph1ent['nat_traversal'] == 'off') {
+ $forceencaps = 'forceencaps = no';
+ } else if ($ph1ent['nat_traversal'] == 'force') {
+ $forceencaps = 'forceencaps = yes';
+ } else {
+ $forceencaps = 'forceencaps = no';
+ }
+
+ if ($ph1ent['mobike'] == 'on') {
+ $mobike = 'mobike = yes';
+ } else {
+ $mobike = 'mobike = no';
+ }
+
+ $ipseclifetime = 0;
+ $rightsubnet_spec = array();
+ $leftsubnet_spec = array();
+ $reqids = array();
+ $ealgoAHsp2arr = array();
+ $ealgoESPsp2arr = array();
+ if (is_array($a_phase2) && count($a_phase2)) {
+ foreach ($a_phase2 as $ph2ent) {
+ if ($ikeid != $ph2ent['ikeid']) {
+ continue;
+ }
+
+ if (isset($ph2ent['disabled'])) {
+ continue;
+ }
+
+ if (isset($ph2ent['mobile']) && !isset($a_client['enable'])) {
+ continue;
+ }
+
+ if (($ph2ent['mode'] == 'tunnel') or ($ph2ent['mode'] == 'tunnel6')) {
+ $tunneltype = "type = tunnel";
+
+ $localid_type = $ph2ent['localid']['type'];
+ $leftsubnet_data = ipsec_idinfo_to_cidr($ph2ent['localid'], false, $ph2ent['mode']);
+
+ /* Do not print localid in some cases, such as a pure-psk or psk/xauth single phase2 mobile tunnel */
+ if (($localid_type == "none" || $localid_type == "mobile") &&
+ isset($ph1ent['mobile']) && (ipsec_get_number_of_phase2($ikeid) == 1)) {
+ $left_spec = '%any';
+ } else {
+ if ($localid_type != "address") {
+ $localid_type = "subnet";
+ }
+ // Don't let an empty subnet into config, it can cause parse errors. Ticket #2201.
+ if (!is_ipaddr($leftsubnet_data) && !is_subnet($leftsubnet_data) && ($leftsubnet_data != "0.0.0.0/0")) {
+ log_error("Invalid IPsec Phase 2 \"{$ph2ent['descr']}\" - {$ph2ent['localid']['type']} has no subnet.");
+ continue;
+ }
+ if (!empty($ph2ent['natlocalid'])) {
+ $natleftsubnet_data = ipsec_idinfo_to_cidr($ph2ent['natlocalid'], false, $ph2ent['mode']);
+ if ($ph2ent['natlocalid']['type'] != "address") {
+ if (is_subnet($natleftsubnet_data)) {
+ $leftsubnet_data = "{$natleftsubnet_data}|{$leftsubnet_data}";
+ }
+ } else {
+ if (is_ipaddr($natleftsubnet_data)) {
+ $leftsubnet_data = "{$natleftsubnet_data}|{$leftsubnet_data}";
+ }
+ }
+ $natfilterrules = true;
+ }
+ }
+
+ $leftsubnet_spec[] = $leftsubnet_data;
+
+ if (!isset($ph2ent['mobile'])) {
+ $tmpsubnet = ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']);
+ $rightsubnet_spec[] = $tmpsubnet;
+ } else if (!empty($a_client['pool_address'])) {
+ $rightsubnet_spec[] = "{$a_client['pool_address']}/{$a_client['pool_netbits']}";
+ }
+ } else {
+ $tunneltype = "type = transport";
+
+ if ((($ph1ent['authentication_method'] == "xauth_psk_server") ||
+ ($ph1ent['authentication_method'] == "pre_shared_key")) && isset($ph1ent['mobile'])) {
+ $left_spec = "%any";
+ } else {
+ $tmpsubnet = ipsec_get_phase1_src($ph1ent);
+ $leftsubnet_spec[] = $tmpsubnet;
+ }
+
+ if (!isset($ph2ent['mobile'])) {
+ $rightsubnet_spec[] = $right_spec;
+ }
+ }
+
+ if (isset($a_client['pfs_group']) && isset($ph2ent['mobile'])) {
+ $ph2ent['pfsgroup'] = $a_client['pfs_group'];
+ }
+
+ if ($ph2ent['protocol'] == 'esp') {
+ if (is_array($ph2ent['encryption-algorithm-option'])) {
+ foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
+ $ealg_id = $ealg['name'];
+ $ealg_kl = $ealg['keylen'];
+
+ if (!empty($ealg_kl) && $ealg_kl == "auto") {
+ if (empty($p2_ealgos) || !is_array($p2_ealgos)) {
+ require("ipsec.inc");
+ }
+ $key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
+ $key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
+ $key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
+ /* XXX: in some cases where include ordering is suspect these variables
+ * are somehow 0 and we enter this loop forever and timeout after 900
+ * seconds wrecking bootup */
+ if ($key_hi != 0 and $key_lo != 0 and $key_step != 0) {
+ for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
+ if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) {
+ foreach ($ph2ent['hash-algorithm-option'] as $halgo) {
+ $halgo = str_replace('hmac_', '', $halgo);
+ $tmpealgo = "{$ealg_id}{$keylen}-{$halgo}";
+ $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']);
+ if (!empty($modp)) {
+ $tmpealgo .= "-{$modp}";
+ }
+ $ealgoESPsp2arr[] = $tmpealgo;
+ }
+ } else {
+ $tmpealgo = "{$ealg_id}{$keylen}";
+ $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']);
+ if (!empty($modp)) {
+ $tmpealgo .= "-{$modp}";
+ }
+ $ealgoESPsp2arr[] = $tmpealgo;
+ }
+ }
+ }
+ } else {
+ if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) {
+ foreach ($ph2ent['hash-algorithm-option'] as $halgo) {
+ $halgo = str_replace('hmac_', '', $halgo);
+ $tmpealgo = "{$ealg_id}{$ealg_kl}-{$halgo}";
+ $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']);
+ if (!empty($modp)) {
+ $tmpealgo .= "-{$modp}";
+ }
+ $ealgoESPsp2arr[] = $tmpealgo;
+ }
+ } else {
+ $tmpealgo = "{$ealg_id}{$ealg_kl}";
+ $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']);
+ if (!empty($modp)) {
+ $tmpealgo .= "-{$modp}";
+ }
+ $ealgoESPsp2arr[] = $tmpealgo;
+ }
+ }
+ }
+ }
+ } else if ($ph2ent['protocol'] == 'ah') {
+ if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) {
+ $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']);
+ foreach ($ph2ent['hash-algorithm-option'] as $tmpAHalgo) {
+ $tmpAHalgo = str_replace('hmac_', '', $tmpAHalgo);
+ if (!empty($modp)) {
+ $tmpAHalgo = "-{$modp}";
+ }
+ $ealgoAHsp2arr[] = $tmpAHalgo;
+ }
+ }
+ }
+
+ $reqids[] = $ph2ent['reqid'];
+
+ if (!empty($ph2ent['lifetime'])) {
+ if ($ipseclifetime == 0 || intval($ipseclifetime) > intval($ph2ent['lifetime'])) {
+ $ipseclifetime = intval($ph2ent['lifetime']);
+ }
+ }
+
+ }
+ }
+
+ $ipsecconnect =<<<EOD
+ fragmentation = yes
+ keyexchange = {$keyexchange}
+ {$reauth}
+ {$forceencaps}
+ {$mobike}
+ {$rekey}
+ installpolicy = yes
+ {$tunneltype}
+ {$dpdline}
+ auto = {$passive}
+ left = {$left_spec}
+ right = {$right_spec}
+ {$leftid}
+
+EOD;
+
+ if (isset($config['ipsec']['compression'])) {
+ $ipsecconnect .= "\tcompress = yes\n";
+ $enablecompression = true;
+ }
+ if (!empty($ikelifeline)) {
+ $ipsecconnect .= "\t{$ikelifeline}\n";
+ }
+ if ($ipseclifetime > 0) {
+ $ipsecconnect .= "\tlifetime = {$ipseclifetime}s\n";
+ }
+ if (!empty($rightsourceip)) {
+ $ipsecconnect .= "{$rightsourceip}";
+ }
+ if (!empty($ealgosp1)) {
+ $ipsecconnect .= "\t{$ealgosp1}\n";
+ }
+ if (!empty($ealgoAHsp2arr)) {
+ $ipsecconnect .= "\tah = " . join(',', $ealgoAHsp2arr) . "!\n";
+ }
+ if (!empty($ealgoESPsp2arr)) {
+ $ipsecconnect .= "\tesp = " . join(',', $ealgoESPsp2arr) . "!\n";
+ }
+ if (!empty($authentication)) {
+ $ipsecconnect .= "\t{$authentication}\n";
+ }
+ if (!empty($peerid_spec)) {
+ $ipsecconnect .= "\trightid = {$peerid_spec}\n";
+ }
+ if ($keyexchange == 'ikev1') {
+ $ipsecconnect .= "\taggressive = {$aggressive}\n";
+ }
+
+ if (!isset($ph1ent['mobile']) && $keyexchange == 'ikev1') {
+ if (!empty($rightsubnet_spec)) {
+ $ipsecfin = '';
+ foreach ($rightsubnet_spec as $idx => $rsubnet) {
+ $ipsecfin .= "\nconn con{$ph1ent['ikeid']}00{$idx}\n";
+ //if (!empty($reqids[$idx])) {
+ // $ipsecfin .= "\treqid = " . $reqids[$idx] . "\n";
+ //}
+ $ipsecfin .= $ipsecconnect;
+ $ipsecfin .= "\trightsubnet = {$rsubnet}\n";
+ $ipsecfin .= "\tleftsubnet = " . $leftsubnet_spec[$idx] . "\n";
+ }
+ } else {
+ log_error("No phase2 specifications for tunnel with REQID = {$ikeid}");
+ }
+ } else {
+ $ipsecfin = "\nconn con{$ph1ent['ikeid']}\n";
+ //if (!empty($reqids[$idx])) {
+ // $ipsecfin .= "\treqid = " . $reqids[0] . "\n";
+ //}
+ $ipsecfin .= $ipsecconnect;
+ if (!isset($ph1ent['mobile']) && !empty($rightsubnet_spec)) {
+ $tempsubnets = array();
+ foreach ($rightsubnet_spec as $rightsubnet) {
+ $tempsubnets[$rightsubnet] = $rightsubnet;
+ }
+ $ipsecfin .= "\trightsubnet = " . join(",", $tempsubnets) . "\n";
+ unset($tempsubnets, $rightsubnet);
+ }
+ if (!empty($leftsubnet_spec)) {
+ $tempsubnets = array();
+ foreach ($leftsubnet_spec as $leftsubnet) {
+ $tempsubnets[$leftsubnet] = $leftsubnet;
+ }
+ $ipsecfin .= "\tleftsubnet = " . join(",", $tempsubnets) . "\n";
+ unset($tempsubnets, $leftsubnet);
+ }
+ }
+ $ipsecconf .= $ipsecfin;
+ unset($ipsecfin);
+ }
+ }
+
+ @file_put_contents("{$g['varetc_path']}/ipsec/ipsec.conf", $ipsecconf);
+ unset($ipsecconf);
+ /* end ipsec.conf */
+
+ if ($enablecompression === true) {
+ set_single_sysctl('net.inet.ipcomp.ipcomp_enable', 1);
+ } else {
+ set_single_sysctl('net.inet.ipcomp.ipcomp_enable', 0);
+ }
+
+ /* manage process */
+ if ($restart === true) {
+ mwexec("/usr/local/sbin/ipsec restart", false);
+ } else {
+ if (isvalidpid("{$g['varrun_path']}/starter.charon.pid")) {
+ /* Update configuration changes */
+ /* Read secrets */
+ mwexec("/usr/local/sbin/ipsec rereadall", false);
+ mwexec("/usr/local/sbin/ipsec reload", false);
+ } else {
+ mwexec("/usr/local/sbin/ipsec start", false);
+ }
+ }
+
+ if ($natfilterrules == true) {
+ filter_configure();
+ }
+ /* start filterdns, if necessary */
+ if (count($filterdns_list) > 0) {
+ $interval = 60;
+ if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval'])) {
+ $interval = $ipseccfg['dns-interval'];
+ }
+
+ $hostnames = "";
+ array_unique($filterdns_list);
+ foreach ($filterdns_list as $hostname) {
+ $hostnames .= "cmd {$hostname} '/usr/local/sbin/pfSctl -c \"service reload ipsecdns\"'\n";
+ }
+ file_put_contents("{$g['varetc_path']}/ipsec/filterdns-ipsec.hosts", $hostnames);
+ unset($hostnames);
+
+ if (isvalidpid("{$g['varrun_path']}/filterdns-ipsec.pid")) {
+ sigkillbypid("{$g['varrun_path']}/filterdns-ipsec.pid", "HUP");
+ } else {
+ mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-ipsec.pid -i {$interval} -c {$g['varetc_path']}/ipsec/filterdns-ipsec.hosts -d 1");
+ }
+ } else {
+ killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
+ @unlink("{$g['varrun_path']}/filterdns-ipsec.pid");
+ }
+
+ if (platform_booting()) {
+ echo "done\n";
+ }
+
+ return count($filterdns_list);
+}
+
+/*
+ * Forcefully restart IPsec
+ * This is required for when dynamic interfaces reload
+ * For all other occasions the normal vpn_ipsec_configure()
+ * will gracefully reload the settings without restarting
+ */
+function vpn_ipsec_force_reload($interface = "") {
+ global $g, $config;
+
+ $ipseccfg = $config['ipsec'];
+
+ if (!empty($interface) && is_array($ipseccfg['phase1'])) {
+ $found = false;
+ foreach ($ipseccfg['phase1'] as $ipsec) {
+ if (!isset($ipsec['disabled']) && ($ipsec['interface'] == $interface)) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ log_error(sprintf(gettext("Ignoring IPsec reload since there are no tunnels on interface %s"), $interface));
+ return;
+ }
+ }
+
+ /* if ipsec is enabled, start up again */
+ if (isset($ipseccfg['enable'])) {
+ log_error(gettext("Forcefully reloading IPsec"));
+ vpn_ipsec_configure();
+ }
+}
+
+/* master setup for vpn (mpd) */
+function vpn_setup() {
+ /* start pptpd */
+ vpn_pptpd_configure();
+
+ /* start pppoe server */
+ vpn_pppoes_configure();
+
+ /* setup l2tp */
+ vpn_l2tp_configure();
+}
+
+function vpn_netgraph_support() {
+ $iflist = get_configured_interface_list();
+ foreach ($iflist as $iface) {
+ $realif = get_real_interface($iface);
+ /* Get support for netgraph(4) from the nic */
+ $ifinfo = pfSense_get_interface_addresses($realif);
+ if (!empty($ifinfo) && in_array($ifinfo['iftype'], array("ether", "vlan", "bridge"))) {
+ pfSense_ngctl_attach(".", $realif);
+ }
+ }
+}
+
+function vpn_pptpd_configure() {
+ global $config, $g;
+
+ $syscfg = $config['system'];
+ $pptpdcfg = $config['pptpd'];
+
+ if (platform_booting()) {
+ if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off")) {
+ return 0;
+ }
+
+ if (platform_booting(true)) {
+ echo gettext("Configuring PPTP VPN service... ");
+ }
+ } else {
+ /* kill mpd */
+ killbypid("{$g['varrun_path']}/pptp-vpn.pid");
+
+ /* wait for process to die */
+ sleep(3);
+
+ if (is_process_running("mpd -b")) {
+ killbypid("{$g['varrun_path']}/pptp-vpn.pid");
+ log_error(gettext("Could not kill mpd within 3 seconds. Trying again."));
+ }
+
+ /* remove mpd.conf, if it exists */
+ unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.conf");
+ unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.links");
+ unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.secret");
+ }
+
+ if (empty($pptpdcfg['n_pptp_units'])) {
+ log_error("Something wrong in the PPTPd configuration. Preventing starting the daemon because issues would arise.");
+ return;
+ }
+
+ /* make sure pptp-vpn directory exists */
+ if (!file_exists("{$g['varetc_path']}/pptp-vpn")) {
+ mkdir("{$g['varetc_path']}/pptp-vpn");
+ }
+
+ switch ($pptpdcfg['mode']) {
+ case 'server':
+ /* write mpd.conf */
+ $fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.conf", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.conf in vpn_pptpd_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdconf = <<<EOD
+pptps:
+
+EOD;
+
+ for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
+ $mpdconf .= " load pt{$i}\n";
+ }
+
+ for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
+
+ $clientip = long2ip32(ip2long($pptpdcfg['remoteip']) + $i);
+
+ $mpdconf .= <<<EOD
+
+pt{$i}:
+ new -i pptpd{$i} pt{$i} pt{$i}
+ set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
+ load pts
+
+EOD;
+ }
+
+ $mpdconf .=<<<EOD
+
+pts:
+ set iface disable on-demand
+ set iface enable proxy-arp
+ set iface enable tcpmssfix
+ set iface idle 1800
+ set iface up-script /usr/local/sbin/vpn-linkup
+ set iface down-script /usr/local/sbin/vpn-linkdown
+ set bundle enable multilink
+ set bundle enable crypt-reqd
+ set link yes acfcomp protocomp
+ set link no pap chap
+ set link enable chap-msv2
+ set link mtu 1460
+ set link keep-alive 10 60
+ set ipcp yes vjcomp
+ set bundle enable compression
+ set ccp yes mppc
+ set ccp yes mpp-e128
+ set ccp yes mpp-stateless
+
+EOD;
+
+ if (!isset ($pptpdcfg['req128'])) {
+ $mpdconf .=<<<EOD
+ set ccp yes mpp-e40
+ set ccp yes mpp-e56
+
+EOD;
+ }
+
+ if (isset($pptpdcfg["wins"]) && $pptpdcfg['wins'] != "") {
+ $mpdconf .= " set ipcp nbns {$pptpdcfg['wins']}\n";
+ }
+
+ if (!empty($pptpdcfg['dns1'])) {
+ $mpdconf .= " set ipcp dns " . $pptpdcfg['dns1'];
+ if (!empty($pptpdcfg['dns2'])) {
+ $mpdconf .= " " . $pptpdcfg['dns2'];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset ($config['dnsmasq']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset($config['unbound']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
+ $mpdconf .= " set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
+ }
+
+ if (isset ($pptpdcfg['radius']['server']['enable'])) {
+ $authport = (isset($pptpdcfg['radius']['server']['port']) && strlen($pptpdcfg['radius']['server']['port']) > 1) ? $pptpdcfg['radius']['server']['port'] : 1812;
+ $acctport = $authport + 1;
+ $mpdconf .=<<<EOD
+ set radius server {$pptpdcfg['radius']['server']['ip']} "{$pptpdcfg['radius']['server']['secret']}" {$authport} {$acctport}
+
+EOD;
+ if (isset ($pptpdcfg['radius']['server2']['enable'])) {
+ $authport = (isset($pptpdcfg['radius']['server2']['port']) && strlen($pptpdcfg['radius']['server2']['port']) > 1) ? $pptpdcfg['radius']['server2']['port'] : 1812;
+ $acctport = $authport + 1;
+ $mpdconf .=<<<EOD
+ set radius server {$pptpdcfg['radius']['server2']['ip']} "{$pptpdcfg['radius']['server2']['secret2']}" {$authport} {$acctport}
+
+EOD;
+ }
+ $mpdconf .=<<<EOD
+ set radius retries 3
+ set radius timeout 10
+ set auth enable radius-auth
+
+EOD;
+
+ if (isset ($pptpdcfg['radius']['accounting'])) {
+ $mpdconf .=<<<EOD
+ set auth enable radius-acct
+ set radius acct-update 300
+
+EOD;
+ }
+ }
+
+ fwrite($fd, $mpdconf);
+ fclose($fd);
+ unset($mpdconf);
+
+ /* write mpd.links */
+ $fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.links", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.links in vpn_pptpd_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdlinks = "";
+
+ for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
+ $mpdlinks .=<<<EOD
+
+pt{$i}:
+ set link type pptp
+ set pptp enable incoming
+ set pptp disable originate
+ set pptp disable windowing
+
+EOD;
+ }
+
+ fwrite($fd, $mpdlinks);
+ fclose($fd);
+ unset($mpdlinks);
+
+ /* write mpd.secret */
+ $fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.secret", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.secret in vpn_pptpd_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdsecret = "";
+
+ if (is_array($pptpdcfg['user'])) {
+ foreach ($pptpdcfg['user'] as $user) {
+ $pass = str_replace('\\', '\\\\', $user['password']);
+ $pass = str_replace('"', '\"', $pass);
+ $mpdsecret .= "{$user['name']} \"{$pass}\" {$user['ip']}\n";
+ }
+ }
+
+ fwrite($fd, $mpdsecret);
+ fclose($fd);
+ unset($mpdsecret);
+ chmod("{$g['varetc_path']}/pptp-vpn/mpd.secret", 0600);
+
+ vpn_netgraph_support();
+
+ /* fire up mpd */
+ mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pptp-vpn -p {$g['varrun_path']}/pptp-vpn.pid -s pptps pptps");
+
+ break;
+
+ case 'redir':
+ break;
+ }
+
+ if (platform_booting()) {
+ echo "done\n";
+ }
+
+ return 0;
+}
+
+function vpn_pppoes_configure() {
+ global $config;
+
+ if (is_array($config['pppoes']['pppoe'])) {
+ foreach ($config['pppoes']['pppoe'] as $pppoe) {
+ vpn_pppoe_configure($pppoe);
+ }
+ }
+}
+
+function vpn_pppoe_configure(&$pppoecfg) {
+ global $config, $g;
+
+ $syscfg = $config['system'];
+
+ /* create directory if it does not exist */
+ if (!is_dir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn")) {
+ mkdir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn");
+ }
+
+ if (platform_booting()) {
+ if (!$pppoecfg['mode'] || ($pppoecfg['mode'] == "off")) {
+ return 0;
+ }
+
+ echo gettext("Configuring PPPoE Server service... ");
+ } else {
+ /* kill mpd */
+ killbypid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid");
+
+ /* wait for process to die */
+ sleep(2);
+
+ }
+
+ switch ($pppoecfg['mode']) {
+
+ case 'server':
+
+ $pppoe_interface = get_real_interface($pppoecfg['interface']);
+
+ if ($pppoecfg['paporchap'] == "chap") {
+ $paporchap = "set link enable chap";
+ } else {
+ $paporchap = "set link enable pap";
+ }
+
+ /* write mpd.conf */
+ $fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.conf", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.conf in vpn_pppoe_configure().") . "\n");
+ return 1;
+ }
+ $mpdconf = "\n\n";
+ $mpdconf .= "poes:\n";
+
+ for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
+ $mpdconf .= " load poes{$pppoecfg['pppoeid']}{$i}\n";
+ }
+
+ for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
+
+ $clientip = long2ip32(ip2long($pppoecfg['remoteip']) + $i);
+
+ if (isset($pppoecfg['radius']['radiusissueips']) && isset($pppoecfg['radius']['server']['enable'])) {
+ $issue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 0.0.0.0/0";
+ } else {
+ $issue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 {$clientip}/32";
+ }
+
+ $mpdconf .=<<<EOD
+
+poes{$pppoecfg['pppoeid']}{$i}:
+ new -i poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i}
+ {$issue_ip_type}
+ load pppoe_standard
+
+EOD;
+ }
+
+ $mpdconf .=<<<EOD
+
+pppoe_standard:
+ set bundle no multilink
+ set bundle enable compression
+ set auth max-logins 1
+ set iface up-script /usr/local/sbin/vpn-linkup
+ set iface down-script /usr/local/sbin/vpn-linkdown
+ set iface idle 0
+ set iface disable on-demand
+ set iface disable proxy-arp
+ set iface enable tcpmssfix
+ set iface mtu 1500
+ set link no pap chap
+ {$paporchap}
+ set link keep-alive 60 180
+ set ipcp yes vjcomp
+ set ipcp no vjcomp
+ set link max-redial -1
+ set link mtu 1492
+ set link mru 1492
+ set ccp yes mpp-e40
+ set ccp yes mpp-e128
+ set ccp yes mpp-stateless
+ set link latency 1
+ #set ipcp dns 10.10.1.3
+ #set bundle accept encryption
+
+EOD;
+
+ if (!empty($pppoecfg['dns1'])) {
+ $mpdconf .= " set ipcp dns " . $pppoecfg['dns1'];
+ if (!empty($pppoecfg['dns2'])) {
+ $mpdconf .= " " . $pppoecfg['dns2'];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset ($config['dnsmasq']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset ($config['unbound']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
+ $mpdconf .= " set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
+ }
+
+ if (isset ($pppoecfg['radius']['server']['enable'])) {
+ $radiusport = "";
+ $radiusacctport = "";
+ if (isset($pppoecfg['radius']['server']['port'])) {
+ $radiusport = $pppoecfg['radius']['server']['port'];
+ }
+ if (isset($pppoecfg['radius']['server']['acctport'])) {
+ $radiusacctport = $pppoecfg['radius']['server']['acctport'];
+ }
+ $mpdconf .=<<<EOD
+ set radius server {$pppoecfg['radius']['server']['ip']} "{$pppoecfg['radius']['server']['secret']}" {$radiusport} {$radiusacctport}
+ set radius retries 3
+ set radius timeout 10
+ set auth enable radius-auth
+
+EOD;
+
+ if (isset ($pppoecfg['radius']['accounting'])) {
+ $mpdconf .=<<<EOD
+ set auth enable radius-acct
+
+EOD;
+ }
+ }
+
+ fwrite($fd, $mpdconf);
+ fclose($fd);
+ unset($mpdconf);
+
+ /* write mpd.links */
+ $fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.links", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.links in vpn_pppoe_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdlinks = "";
+
+ for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
+ $mpdlinks .=<<<EOD
+
+poes{$pppoecfg['pppoeid']}{$i}:
+ set phys type pppoe
+ set pppoe iface {$pppoe_interface}
+ set pppoe service "*"
+ set pppoe disable originate
+ set pppoe enable incoming
+
+EOD;
+ }
+
+ fwrite($fd, $mpdlinks);
+ fclose($fd);
+ unset($mpdlinks);
+
+ if ($pppoecfg['username']) {
+ /* write mpd.secret */
+ $fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.secret in vpn_pppoe_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdsecret = "\n\n";
+
+ if (!empty($pppoecfg['username'])) {
+ $item = explode(" ", $pppoecfg['username']);
+ foreach ($item as $userdata) {
+ $data = explode(":", $userdata);
+ $mpdsecret .= "{$data[0]} \"" . base64_decode($data[1]) . "\" {$data[2]}\n";
+ }
+ }
+
+ fwrite($fd, $mpdsecret);
+ fclose($fd);
+ unset($mpdsecret);
+ chmod("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", 0600);
+ }
+
+ /* Check if previous instance is still up */
+ while (file_exists("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid") && isvalidpid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid")) {
+ killbypid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid");
+ }
+
+ /* Get support for netgraph(4) from the nic */
+ pfSense_ngctl_attach(".", $pppoe_interface);
+ /* fire up mpd */
+ mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn -p {$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid -s poes poes");
+
+ break;
+ }
+
+ if (platform_booting()) {
+ echo gettext("done") . "\n";
+ }
+
+ return 0;
+}
+
+function vpn_l2tp_configure() {
+ global $config, $g;
+
+ $syscfg = $config['system'];
+ $l2tpcfg = $config['l2tp'];
+
+ /* create directory if it does not exist */
+ if (!is_dir("{$g['varetc_path']}/l2tp-vpn")) {
+ mkdir("{$g['varetc_path']}/l2tp-vpn");
+ }
+
+ if (platform_booting()) {
+ if (!$l2tpcfg['mode'] || ($l2tpcfg['mode'] == "off")) {
+ return 0;
+ }
+
+ echo gettext("Configuring l2tp VPN service... ");
+ } else {
+ /* kill mpd */
+ killbypid("{$g['varrun_path']}/l2tp-vpn.pid");
+
+ /* wait for process to die */
+ sleep(8);
+
+ }
+
+ /* make sure l2tp-vpn directory exists */
+ if (!file_exists("{$g['varetc_path']}/l2tp-vpn")) {
+ mkdir("{$g['varetc_path']}/l2tp-vpn");
+ }
+
+ switch ($l2tpcfg['mode']) {
+
+ case 'server':
+ if ($l2tpcfg['paporchap'] == "chap") {
+ $paporchap = "set link enable chap";
+ } else {
+ $paporchap = "set link enable pap";
+ }
+
+ /* write mpd.conf */
+ $fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.conf", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.conf in vpn_l2tp_configure().") . "\n");
+ return 1;
+ }
+ $mpdconf = "\n\n";
+ $mpdconf .=<<<EOD
+l2tps:
+
+EOD;
+
+ for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
+ $mpdconf .= " load l2tp{$i}\n";
+ }
+
+ for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
+
+ $clientip = long2ip32(ip2long($l2tpcfg['remoteip']) + $i);
+
+ if (isset ($l2tpcfg['radius']['radiusissueips']) && isset ($l2tpcfg['radius']['enable'])) {
+ $issue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 0.0.0.0/0";
+ } else {
+ $issue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 {$clientip}/32";
+ }
+
+ $mpdconf .=<<<EOD
+
+l2tp{$i}:
+ new -i l2tp{$i} l2tp{$i} l2tp{$i}
+ {$issue_ip_type}
+ load l2tp_standard
+
+EOD;
+ }
+
+ $mpdconf .=<<<EOD
+
+l2tp_standard:
+ set bundle disable multilink
+ set bundle enable compression
+ set bundle yes crypt-reqd
+ set ipcp yes vjcomp
+ # set ipcp ranges 131.188.69.161/32 131.188.69.170/28
+ set ccp yes mppc
+ set iface disable on-demand
+ set iface enable proxy-arp
+ set iface up-script /usr/local/sbin/vpn-linkup
+ set iface down-script /usr/local/sbin/vpn-linkdown
+ set link yes acfcomp protocomp
+ set link no pap chap
+ {$paporchap}
+ set link keep-alive 10 180
+
+EOD;
+
+ if (is_ipaddr($l2tpcfg['wins'])) {
+ $mpdconf .= " set ipcp nbns {$l2tpcfg['wins']}\n";
+ }
+ if (is_ipaddr($l2tpcfg['dns1'])) {
+ $mpdconf .= " set ipcp dns " . $l2tpcfg['dns1'];
+ if (is_ipaddr($l2tpcfg['dns2'])) {
+ $mpdconf .= " " . $l2tpcfg['dns2'];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset ($config['dnsmasq']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (isset ($config['unbound']['enable'])) {
+ $mpdconf .= " set ipcp dns " . get_interface_ip("lan");
+ if ($syscfg['dnsserver'][0]) {
+ $mpdconf .= " " . $syscfg['dnsserver'][0];
+ }
+ $mpdconf .= "\n";
+ } elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
+ $mpdconf .= " set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
+ }
+
+ if (isset ($l2tpcfg['radius']['enable'])) {
+ $mpdconf .=<<<EOD
+ set radius server {$l2tpcfg['radius']['server']} "{$l2tpcfg['radius']['secret']}"
+ set radius retries 3
+ set radius timeout 10
+ set auth enable radius-auth
+
+EOD;
+
+ if (isset ($l2tpcfg['radius']['accounting'])) {
+ $mpdconf .=<<<EOD
+ set auth enable radius-acct
+
+EOD;
+ }
+ }
+
+ fwrite($fd, $mpdconf);
+ fclose($fd);
+ unset($mpdconf);
+
+ /* write mpd.links */
+ $fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.links", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.links in vpn_l2tp_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdlinks = "";
+
+ for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
+ $mpdlinks .=<<<EOD
+
+l2tp{$i}:
+ set link type l2tp
+ set l2tp enable incoming
+ set l2tp disable originate
+
+EOD;
+ if (!empty($l2tpcfg['secret'])) {
+ $mpdlinks .= "set l2tp secret {$l2tpcfg['secret']}\n";
+ }
+ }
+
+ fwrite($fd, $mpdlinks);
+ fclose($fd);
+ unset($mpdlinks);
+
+ /* write mpd.secret */
+ $fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.secret", "w");
+ if (!$fd) {
+ printf(gettext("Error: cannot open mpd.secret in vpn_l2tp_configure().") . "\n");
+ return 1;
+ }
+
+ $mpdsecret = "\n\n";
+
+ if (is_array($l2tpcfg['user'])) {
+ foreach ($l2tpcfg['user'] as $user) {
+ $mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
+ }
+ }
+
+ fwrite($fd, $mpdsecret);
+ fclose($fd);
+ unset($mpdsecret);
+ chmod("{$g['varetc_path']}/l2tp-vpn/mpd.secret", 0600);
+
+ vpn_netgraph_support();
+
+ /* fire up mpd */
+ mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/l2tp-vpn -p {$g['varrun_path']}/l2tp-vpn.pid -s l2tps l2tps");
+
+ break;
+
+ case 'redir':
+ break;
+ }
+
+ if (platform_booting()) {
+ echo "done\n";
+ }
+
+ return 0;
+}
+
+?>
diff --git a/src/etc/inc/vslb.inc b/src/etc/inc/vslb.inc
new file mode 100644
index 0000000..05bef31
--- /dev/null
+++ b/src/etc/inc/vslb.inc
@@ -0,0 +1,564 @@
+<?php
+/* $Id$ */
+/*
+ vslb.inc
+ Copyright (C) 2005-2008 Bill Marquette
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+/*
+ pfSense_BUILDER_BINARIES: /usr/local/sbin/relayd
+ pfSense_MODULE: routing
+*/
+
+
+/* include all configuration functions */
+
+class Monitor {
+ private $conf = array();
+ function __construct($config) {
+ $this->conf = $config;
+ }
+
+ public function p() {
+ return "check {$this->get('proto')}";
+ }
+ private function get($var) {
+ return isset($this->$var) ? $this->$var : "";
+ }
+ protected function config($element) {
+ return isset($this->conf[$element]) ? $this->conf[$element] : "";
+ }
+}
+
+class TCPMonitor extends Monitor {
+ protected $proto = 'tcp';
+}
+
+class SSLMonitor extends Monitor {
+ protected $proto = 'ssl';
+}
+
+class ICMPMonitor extends Monitor {
+ protected $proto = 'icmp';
+}
+
+class HTTPMonitor extends Monitor {
+ protected $proto = 'http';
+ function __construct($config) {
+ parent::__construct($config);
+ }
+ public function p() {
+ $method = ($this->code() != "") ? $this->code() : $this->digest();
+ return "check {$this->proto} {$this->path()} {$this->host()} {$method}";
+ }
+
+ private function path() {
+ return $this->config('path') != "" ? "'{$this->config('path')}'" : "";
+ }
+
+ private function host() {
+ return $this->config('host') != "" ? "host {$this->config('host')}" : "";
+ }
+
+ private function code() {
+ return $this->config('code') != "" ? "code {$this->config('code')}" : "";
+ }
+
+ private function digest() {
+ return $this->config('digest') != "" ? "digest {$this->config('digest')}" : "";
+ }
+}
+
+class HTTPSMonitor extends HTTPMonitor {
+ protected $proto = 'https';
+}
+
+class SendMonitor extends Monitor {
+ private $proto = 'send';
+ function __construct($config) {
+ parent::__construct($config);
+ }
+ public function p() {
+ return "check {$this->proto} {$this->data()} expect {$this->pattern()} {$this->ssl()}";
+ }
+
+
+ private function data() {
+ return $this->config('send') != "" ? "\"{$this->config('send')}\"" : "\"\"";
+ }
+
+ private function pattern() {
+ return $this->config('expect') != "" ? "\"{$this->config('expect')}\"" : "\"\"";
+ }
+
+ private function ssl() {
+ return $this->config('ssl') == true ? "ssl" : "";
+ }
+}
+
+function echo_lbaction($action) {
+ global $config;
+
+ // Index actions by name
+ $actions_a = array();
+ for ($i = 0; isset($config['load_balancer']['lbaction'][$i]); $i++) {
+ $actions_a[$config['load_balancer']['lbaction'][$i]['name']] = $config['load_balancer']['lbaction'][$i];
+ }
+
+ $ret = "";
+ $ret .= "{$actions_a[$action]['direction']} {$actions_a[$action]['type']} {$actions_a[$action]['action']}";
+ switch ($actions_a[$action]['action']) {
+ case 'append':
+ $ret .= " \"{$actions_a[$action]['options']['value']}\" to \"{$actions_a[$action]['options']['akey']}\"";
+ break;
+ case 'change':
+ $ret .= " \"{$actions_a[$action]['options']['akey']}\" to \"{$actions_a[$action]['options']['value']}\"";
+ break;
+ case 'expect':
+ $ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
+ break;
+ case 'filter':
+ $ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
+ break;
+ case 'hash':
+ $ret .= " \"{$actions_a[$action]['options']['akey']}\"";
+ break;
+ case 'log':
+ $ret .= " \"{$actions_a[$action]['options']['akey']}\"";
+ break;
+ }
+ return $ret;
+}
+
+function relayd_configure($kill_first=false) {
+ global $config, $g;
+
+ // have to do this until every call to filter.inc is
+ // require_once() instead of require().
+ if (!function_exists('filter_expand_alias_array')) {
+ require_once("filter.inc");
+ }
+
+ $vs_a = $config['load_balancer']['virtual_server'];
+ $pool_a = $config['load_balancer']['lbpool'];
+ $protocol_a = $config['load_balancer']['lbprotocol'];
+ $setting = $config['load_balancer']['setting'];
+
+ $check_a = array();
+
+ foreach ((array)$config['load_balancer']['monitor_type'] as $type) {
+ switch ($type['type']) {
+ case 'icmp':
+ $mon = new ICMPMonitor($type['options']);
+ break;
+ case 'tcp':
+ $mon = new TCPMonitor($type['options']);
+ break;
+ case 'http':
+ $mon = new HTTPMonitor($type['options']);
+ break;
+ case 'https':
+ $mon = new HTTPSMonitor($type['options']);
+ break;
+ case 'send':
+ $mon = new SendMonitor($type['options']);
+ break;
+ }
+ if ($mon) {
+ $check_a[$type['name']] = $mon->p();
+ }
+ }
+
+
+ $fd = fopen("{$g['varetc_path']}/relayd.conf", "w");
+ $conf .= "log updates \n";
+
+ /* Global timeout, interval and prefork settings
+ if not specified by the user:
+ - use a 1000 ms timeout value as in pfsense 2.0.1 and above
+ - leave interval and prefork empty, relayd will use its default values */
+
+ if (isset($setting['timeout']) && !empty($setting['timeout'])) {
+ $conf .= "timeout ".$setting['timeout']." \n";
+ } else {
+ $conf .= "timeout 1000 \n";
+ }
+
+ if (isset($setting['interval']) && !empty($setting['interval'])) {
+ $conf .= "interval ".$setting['interval']." \n";
+ }
+
+ if (isset($setting['prefork']) && !empty($setting['prefork'])) {
+ $conf .= "prefork ".$setting['prefork']." \n";
+ }
+
+ /* reindex pools by name as we loop through the pools array */
+ $pools = array();
+ /* Virtual server pools */
+ if (is_array($pool_a)) {
+ for ($i = 0; isset($pool_a[$i]); $i++) {
+ if (is_array($pool_a[$i]['servers'])) {
+ if (!empty($pool_a[$i]['retry'])) {
+ $retrytext = " retry {$pool_a[$i]['retry']}";
+ } else {
+ $retrytext = "";
+ }
+ $conf .= "table <{$pool_a[$i]['name']}> {\n";
+ foreach ($pool_a[$i]['servers'] as $server) {
+ if (is_subnetv4($server)) {
+ foreach (subnetv4_expand($server) as $ip) {
+ $conf .= "\t{$ip}{$retrytext}\n";
+ }
+ } else {
+ $conf .= "\t{$server}{$retrytext}\n";
+ }
+ }
+ $conf .= "}\n";
+ /* Index by name for easier fetching when we loop through the virtual servers */
+ $pools[$pool_a[$i]['name']] = $pool_a[$i];
+ }
+ }
+ }
+// if (is_array($protocol_a)) {
+// for ($i = 0; isset($protocol_a[$i]); $i++) {
+// $proto = "{$protocol_a[$i]['type']} protocol \"{$protocol_a[$i]['name']}\" {\n";
+// if (is_array($protocol_a[$i]['lbaction'])) {
+// if ($protocol_a[$i]['lbaction'][0] == "") {
+// continue;
+// }
+// for ($a = 0; isset($protocol_a[$i]['lbaction'][$a]); $a++) {
+// $proto .= " " . echo_lbaction($protocol_a[$i]['lbaction'][$a]) . "\n";
+// }
+// }
+// $proto .= "}\n";
+// $conf .= $proto;
+// }
+// }
+
+ $conf .= "dns protocol \"dnsproto\" {\n";
+ $conf .= "\t" . "tcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
+ $conf .= "}\n";
+
+ if (is_array($vs_a)) {
+ for ($i = 0; isset($vs_a[$i]); $i++) {
+
+ $append_port_to_name = false;
+ if (is_alias($pools[$vs_a[$i]['poolname']]['port'])) {
+ $dest_port_array = filter_expand_alias_array($pools[$vs_a[$i]['poolname']]['port']);
+ $append_port_to_name = true;
+ } else {
+ $dest_port_array = array($pools[$vs_a[$i]['poolname']]['port']);
+ }
+ if (is_alias($vs_a[$i]['port'])) {
+ $src_port_array = filter_expand_alias_array($vs_a[$i]['port']);
+ $append_port_to_name = true;
+ } else if ($vs_a[$i]['port']) {
+ $src_port_array = array($vs_a[$i]['port']);
+ } else {
+ $src_port_array = $dest_port_array;
+ }
+
+ $append_ip_to_name = false;
+ if (is_alias($vs_a[$i]['ipaddr'])) {
+ $ip_list = array();
+ foreach (filter_expand_alias_array($vs_a[$i]['ipaddr']) as $item) {
+ log_error("item is $item");
+ if (is_subnetv4($item)) {
+ $ip_list = array_merge($ip_list, subnetv4_expand($item));
+ } else {
+ $ip_list[] = $item;
+ }
+ }
+ $append_ip_to_name = true;
+ } else if (is_subnetv4($vs_a[$i]['ipaddr'])) {
+ $ip_list = subnetv4_expand($vs_a[$i]['ipaddr']);
+ $append_ip_to_name = true;
+ } else {
+ $ip_list = array($vs_a[$i]['ipaddr']);
+ }
+
+ for ($j = 0; $j < count($ip_list); $j += 1) {
+ $ip = $ip_list[$j];
+ for ($k = 0; $k < count($src_port_array) && $k < count($dest_port_array); $k += 1) {
+ $src_port = $src_port_array[$k];
+ $dest_port = $dest_port_array[$k];
+ if (is_portrange($dest_port)) {
+ $dest_ports = explode(':', $dest_port);
+ $dest_port = $dest_ports[0];
+ }
+
+ $name = $vs_a[$i]['name'];
+ if ($append_ip_to_name) {
+ $name .= "_" . $j;
+ }
+ if ($append_port_to_name) {
+ $name .= "_" . str_replace(":", "_", $src_port);
+ }
+
+ if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
+ $conf .= "relay \"{$name}\" {\n";
+ $conf .= " listen on {$ip} port {$src_port}\n";
+
+ if ($vs_a[$i]['relay_protocol'] == "dns") {
+ $conf .= " protocol \"dnsproto\"\n";
+ } else {
+ $conf .= " protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
+ }
+ $lbmode = "";
+ if ($pools[$vs_a[$i]['poolname']]['mode'] == "loadbalance") {
+ $lbmode = "mode loadbalance";
+ }
+
+ $conf .= " forward to <{$vs_a[$i]['poolname']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
+
+ if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0 && ($vs_a[$i]['relay_protocol'] != 'dns')) {
+ $conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
+ }
+ $conf .= "}\n";
+ } else {
+ $conf .= "redirect \"{$name}\" {\n";
+ $conf .= " listen on {$ip} port {$src_port}\n";
+ $conf .= " forward to <{$vs_a[$i]['poolname']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
+
+ if (isset($config['system']['lb_use_sticky'])) {
+ $conf .= " sticky-address\n";
+ }
+
+ /* sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing */
+ if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0 && ($vs_a[$i]['relay_protocol'] != 'dns')) {
+ $conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['sitedown']]['monitor']]} \n";
+ }
+
+ $conf .= "}\n";
+ }
+ }
+ }
+ }
+ }
+ fwrite($fd, $conf);
+ fclose($fd);
+
+ if (is_process_running('relayd')) {
+ if (!empty($vs_a)) {
+ if ($kill_first) {
+ mwexec('pkill relayd');
+ /* Remove all active relayd anchors now that relayd is no longer running. */
+ cleanup_lb_anchor("*");
+ mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
+ } else {
+ // it's running and there is a config, just reload
+ mwexec("/usr/local/sbin/relayctl reload");
+ }
+ } else {
+ /*
+ * XXX: Something breaks our control connection with relayd
+ * and makes 'relayctl stop' not work
+ * rule reloads are the current suspect
+ * mwexec('/usr/local/sbin/relayctl stop');
+ * returns "command failed"
+ */
+ mwexec('pkill relayd');
+ /* Remove all active relayd anchors now that relayd is no longer running. */
+ cleanup_lb_anchor("*");
+ }
+ } else {
+ if (!empty($vs_a)) {
+ // not running and there is a config, start it
+ /* Remove all active relayd anchors so it can start fresh. */
+ cleanup_lb_anchor("*");
+ mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
+ }
+ }
+}
+
+function get_lb_redirects() {
+/*
+# relayctl show summary
+Id Type Name Avlblty Status
+1 redirect testvs2 active
+5 table test2:80 active (3 hosts up)
+11 host 192.168.1.2 91.55% up
+10 host 192.168.1.3 100.00% up
+9 host 192.168.1.4 88.73% up
+3 table test:80 active (1 hosts up)
+7 host 192.168.1.2 66.20% down
+6 host 192.168.1.3 97.18% up
+0 redirect testvs active
+3 table test:80 active (1 hosts up)
+7 host 192.168.1.2 66.20% down
+6 host 192.168.1.3 97.18% up
+4 table testvs-sitedown:80 active (1 hosts up)
+8 host 192.168.1.4 84.51% up
+# relayctl show redirects
+Id Type Name Avlblty Status
+1 redirect testvs2 active
+0 redirect testvs active
+# relayctl show redirects
+Id Type Name Avlblty Status
+1 redirect testvs2 active
+ total: 2 sessions
+ last: 2/60s 2/h 2/d sessions
+ average: 1/60s 0/h 0/d sessions
+0 redirect testvs active
+*/
+ $rdr_a = array();
+ exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
+ $relay_a = array();
+ exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
+ $vs = array();
+ $cur_entry = "";
+ for ($i = 0; isset($rdr_a[$i]); $i++) {
+ $line = $rdr_a[$i];
+ if (preg_match("/^[0-9]+/", $line)) {
+ $regs = array();
+ if ($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
+ $cur_entry = trim($regs[1]);
+ $vs[trim($regs[1])] = array();
+ $vs[trim($regs[1])]['status'] = trim($regs[2]);
+ }
+ } elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['total'] = trim($regs[1]);
+ } elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['last'] = trim($regs[1]);
+ } elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['average'] = trim($regs[1]);
+ }
+ }
+ $cur_entry = "";
+ for ($i = 0; isset($relay_a[$i]); $i++) {
+ $line = $relay_a[$i];
+ if (preg_match("/^[0-9]+/", $line)) {
+ $regs = array();
+ if ($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
+ $cur_entry = trim($regs[1]);
+ $vs[trim($regs[1])] = array();
+ $vs[trim($regs[1])]['status'] = trim($regs[2]);
+ }
+ } elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['total'] = trim($regs[1]);
+ } elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['last'] = trim($regs[1]);
+ } elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
+ $vs[$cur_entry]['average'] = trim($regs[1]);
+ }
+ }
+ return $vs;
+}
+
+function get_lb_summary() {
+ $relayctl = array();
+ exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
+ $relay_hosts=Array();
+ foreach ((array) $relayctl as $line) {
+ $t = explode("\t", $line);
+ switch (trim($t[1])) {
+ case "table":
+ $curpool=trim($t[2]);
+ break;
+ case "host":
+ $curhost=trim($t[2]);
+ $relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
+ $relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
+ break;
+ }
+ }
+ return $relay_hosts;
+}
+
+/* Get a list of all relayd virtual server anchors */
+function get_lb_anchors() {
+ /* NOTE: These names come back prepended with "relayd/" e.g. "relayd/MyVSName" */
+ return explode("\n", trim(`/sbin/pfctl -sA -a relayd | /usr/bin/awk '{print $1;}'`));
+}
+
+/* Remove NAT rules from a relayd anchor that is no longer in use.
+ $anchorname can either be * to clear all anchors or a specific anchor name.*/
+function cleanup_lb_anchor($anchorname = "*") {
+ $lbanchors = get_lb_anchors();
+ foreach ($lbanchors as $lba) {
+ if (($anchorname == "*") || ($lba == "relayd/{$anchorname}")) {
+ /* Flush both the NAT and the Table for the anchor, so it will be completely removed by pf. */
+ mwexec("/sbin/pfctl -a " . escapeshellarg($lba) . " -F nat");
+ mwexec("/sbin/pfctl -a " . escapeshellarg($lba) . " -F Tables");
+ }
+ }
+}
+
+/* Mark an anchor for later cleanup. This will allow us to remove an old VS name */
+function cleanup_lb_mark_anchor($name) {
+ global $g;
+ /* Nothing to do! */
+ if (empty($name)) {
+ return;
+ }
+ $filename = "{$g['tmp_path']}/relayd_anchors_remove";
+ $cleanup_anchors = array();
+ /* Read in any currently unapplied name changes */
+ if (file_exists($filename)) {
+ $cleanup_anchors = explode("\n", file_get_contents($filename));
+ }
+ /* Only add the anchor to the list if it's not already there. */
+ if (!in_array($name, $cleanup_anchors)) {
+ $cleanup_anchors[] = $name;
+ }
+ file_put_contents($filename, implode("\n", $cleanup_anchors));
+}
+
+/* Cleanup relayd anchors that have been marked for cleanup. */
+function cleanup_lb_marked() {
+ global $g, $config;
+ $filename = "{$g['tmp_path']}/relayd_anchors_remove";
+ $cleanup_anchors = array();
+ /* Nothing to do! */
+ if (!file_exists($filename)) {
+ return;
+ } else {
+ $cleanup_anchors = explode("\n", file_get_contents($filename));
+ /* Nothing to do! */
+ if (empty($cleanup_anchors)) {
+ return;
+ }
+ }
+
+ /* Load current names so we can make sure we don't remove an anchor that is still in use. */
+ $vs_a = $config['load_balancer']['virtual_server'];
+ $active_vsnames = array();
+ if (is_array($vs_a)) {
+ foreach ($vs_a as $vs) {
+ $active_vsnames[] = $vs['name'];
+ }
+ }
+
+ foreach ($cleanup_anchors as $anchor) {
+ /* Only cleanup an anchor if it is not still active. */
+ if (!in_array($anchor, $active_vsnames)) {
+ cleanup_lb_anchor($anchor);
+ }
+ }
+ unlink_if_exists($filename);
+}
+
+?>
diff --git a/src/etc/inc/wizardapp.inc b/src/etc/inc/wizardapp.inc
new file mode 100644
index 0000000..bf9f699
--- /dev/null
+++ b/src/etc/inc/wizardapp.inc
@@ -0,0 +1,668 @@
+<?php
+/*
+ wizardapp.inc
+ part of pfSense (https://www.pfsense.org/)
+
+ Copyright (C) 2006 Bill Marquette - bill.marquette@gmail.com.
+ Copyright (C) 2006 Scott Ullrich - sullrich@pfsense.com.
+ Copyright (C) 2008-2010 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$gamesplist = array();
+
+/* Game Consoles and Game Clients */
+
+$gamesplist['playstationconsoles'] = array();
+ /* Playstation 3, Playstation 4 and PS Vita */
+ $gamesplist['playstationconsoles'][] = array('PS-Network-TCP', 'tcp', '10040', '10060', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-Network-UDP', 'udp', '50000', '60000', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-Home-TCP-1', 'tcp', '3478', '3480', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-Home-TCP-2', 'tcp', '8080', '8080', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-TCP-1', 'tcp', '5223', '5223', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-TCP-2', 'tcp', '10070', '10080', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-UDP-1', 'udp', '3478', '3479', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-UDP-2', 'udp', '3658', '3658', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-UDP-3', 'udp', '10070', '10070', 'both');
+ $gamesplist['playstationconsoles'][] = array('PS-RemotePlay', 'tcp', '9293', '9293', 'both');
+
+$gamesplist['wiiconsoles'] = array();
+ /* XBox Consoles */
+ $gamesplist['wiiconsoles'][] = array('Wii-Consoles-TCP-1', 'tcp', '6667', '6667', 'both');
+ $gamesplist['wiiconsoles'][] = array('Wii-Consoles-TCP-2', 'tcp', '12400', '12400', 'both');
+ $gamesplist['wiiconsoles'][] = array('Wii-Consoles-TCP-3', 'tcp', '28910', '28910', 'both');
+ $gamesplist['wiiconsoles'][] = array('Wii-Consoles-TCP-4', 'tcp', '29900', '29901', 'both');
+ $gamesplist['wiiconsoles'][] = array('Wii-Consoles-TCP-5', 'tcp', '29920', '29920', 'both');
+
+$gamesplist['xboxconsoles'] = array();
+ /* XBox Consoles */
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-UDP-1', 'udp', '88', '88', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-UDP-2', 'udp', '3074', '3074', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-TCP-1', 'tcp', '3074', '3074', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-TCP-2', 'tcp', '3659', '3659', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-TCP-3', 'tcp', '500', '500', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-TCP-4', 'tcp', '3544', '3544', 'both');
+ $gamesplist['xboxconsoles'][] = array('xbox-Consoles-TCP-5', 'tcp', '4500', '4500', 'both');
+
+$gamesplist['battlenet'] = array();
+ /* Blizzard Publishing games */
+ $gamesplist['battlenet'][] = array('Battle.NET-game1-tcp', 'tcp', '6112', '6119', 'both'); //diablo, diablo2, starcraft, warcraft 2, warcraft 3
+ $gamesplist['battlenet'][] = array('Battle.NET-game1-udp', 'udp', '6112', '6119', 'both'); //diablo, diablo2, starcraft, warcraft 2
+ $gamesplist['battlenet'][] = array('Battle.NET-diablo2', 'tcp', '4000', '4000', 'both'); //diablo2
+ $gamesplist['battlenet'][] = array('Battle.NET-game2', 'tcp', '1119', '1119', 'both'); //diablo3, starcraft 2
+ $gamesplist['battlenet'][] = array('Battle.NET-game3', 'tcp', '3724', '3724', 'both'); //starcraft2
+
+$gamesplist['eaorigin'] = array();
+ /* EA Origin Client */
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-1', 'tcp', '1024', '1124', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-2', 'tcp', '9960', '9969', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-3', 'tcp', '18000', '18000', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-4', 'tcp', '18120', '18120', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-5', 'tcp', '18060', '18060', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-6', 'tcp', '27900', '27900', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-7', 'tcp', '28910', '28910', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-TCP-8', 'tcp', '29900', '29900', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-UDP-1', 'udp', '1024', '1124', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-UDP-2', 'udp', '18000', '18000', 'both');
+ $gamesplist['eaorigin'][] = array('EA-Origin-UDP-3', 'udp', '29900', '29900', 'both');
+
+$gamesplist['steam'] = array();
+ /* Steam Games */
+ $gamesplist['steam'][] = array('Steam-game-udp', 'udp', '27000', '27030', 'both'); //america's army 3, cs:s, cs:go, HL2, COD: Black Ops, COD: Black Ops 2, Natural Selection 2
+ $gamesplist['steam'][] = array('Steam-game-tcp', 'tcp', '27000', '27030', 'both'); //america's army 3, cs:s, cs:go, HL2, COD: Black Ops, COD: Black Ops 2, Natural Selection 2
+ $gamesplist['steam'][] = array('Steam-hltv', 'udp', '27015', '27030', 'both');
+ $gamesplist['steam'][] = array('Steam-1', 'udp', '4380', '4380', 'both');
+ $gamesplist['steam'][] = array('Steam-2', 'udp', '1200', '1200', 'both');
+ $gamesplist['steam'][] = array('Steam-voice', 'udp', '3478', '3480', 'both');
+
+$gamesplist['gamesforwindowslive'] = array();
+ /* Games for Windows Live */
+ $gamesplist['gamesforwindowslive'][] = array('Games4WinLive-1', 'udp', '88', '88', 'both');
+ $gamesplist['gamesforwindowslive'][] = array('Games4WinLive-2', 'udp', '3074', '3074', 'both');
+ $gamesplist['gamesforwindowslive'][] = array('Games4WinLive-3', 'tcp', '3074', '3074', 'both');
+
+/* Games */
+
+$gamesplist['arma2'] = array();
+ /* ARMA 2 */
+ $gamesplist['arma2'][] = array('arma2', 'udp', '2302', '2310', 'both');
+
+$gamesplist['arma3'] = array();
+ /* ARMA 3 */
+ $gamesplist['arma3'][] = array('arma3-game-traffic', 'udp', '2302', '2302', 'both');
+ $gamesplist['arma3'][] = array('arma3-steam-query', 'udp', '2303', '2303', 'both');
+ $gamesplist['arma3'][] = array('arma3-steam-port', 'udp', '2304', '2304', 'both');
+ $gamesplist['arma3'][] = array('arma3-BattleEye-1', 'tcp', '2345', '2345', 'both');
+ $gamesplist['arma3'][] = array('arma3-BattleEye-2', 'tcp', '2344', '2344', 'both');
+ $gamesplist['arma3'][] = array('arma3-BattleEye-2', 'udp', '2344', '2344', 'both');
+
+$gamesplist['battlefield2'] = array();
+ /* Battlefield 2 */
+ $gamesplist['battlefield2'][] = array('BF2-1500-4999', 'udp', '1500', '4999', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-4711', 'tcp', '4711', '4711', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-16567', 'udp', '16567', '16567', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-27900', 'udp', '27900', '27900', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-28910', 'tcp', '28910', '28910', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-29900-29901-UDP', 'udp', '29900', '29901', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-29900-29901-TCP', 'tcp', '29900', '29901', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-27900', 'udp', '27900', '27900', 'both');
+ $gamesplist['battlefield2'][] = array('BF2-55123-55125', 'udp', '55123', '55125', 'both');
+
+$gamesplist['battlefield3'] = array();
+ /* Battlefield 3 and Battlefield 4 */
+ $gamesplist['battlefield3'][] = array('BF3-1', 'tcp', '9988', '9988', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-2', 'tcp', '20000', '20100', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-3', 'tcp', '22990', '22990', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-4', 'tcp', '17502', '17502', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-5', 'tcp', '42127', '42127', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-6', 'udp', '3659', '3659', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-7', 'udp', '14000', '14016', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-8', 'udp', '22990', '23006', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-9', 'udp', '25200', '25300', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-PS-1', 'tcp', '10000', '10100', 'both');
+ $gamesplist['battlefield3'][] = array('BF3-PS-2', 'tcp', '1935', '1935', 'both');
+
+
+$gamesplist['battlefieldbc2'] = array();
+ /* Battlefield Bad Company 2 */
+ $gamesplist['battlefieldbc2'][] = array('BFBC2-1', 'tcp', '18390', '18390', 'both');
+ $gamesplist['battlefieldbc2'][] = array('BFBC2-2', 'tcp', '18395', '18395', 'both');
+ $gamesplist['battlefieldbc2'][] = array('BFBC2-3', 'udp', '18395', '18395', 'both');
+ $gamesplist['battlefieldbc2'][] = array('BFBC2-4', 'tcp', '13505', '13505', 'both');
+
+$gamesplist['borderlands'] = array();
+ /* Borderlands */
+ $gamesplist['borderlands'][] = array('Borderlands-udp', 'udp', '7777', '7777', 'both');
+ $gamesplist['borderlands'][] = array('Borderlands-tcp', 'tcp', '7777', '7777', 'both');
+
+$gamesplist['callofduty'] = array();
+ /* Call Of Duty */
+ $gamesplist['callofduty'][] = array('CallOfDuty1', 'tcp', '28960', '28960', 'both');
+ $gamesplist['callofduty'][] = array('CallOfDuty2', 'udp', '28960', '28960', 'both');
+
+$gamesplist['counterstrike'] = array();
+ /* counter strike */
+ $gamesplist['counterstrike'][] = array('CS-Titan', 'udp', '6003', '6003', 'both');
+ $gamesplist['counterstrike'][] = array('CS-Authentication', 'udp', '7002', '7002', 'both');
+ $gamesplist['counterstrike'][] = array('CS-Client', 'udp', '6003', '6003', 'both');
+ $gamesplist['counterstrike'][] = array('CS-Masterserver', 'udp', '27010', '27010', 'both');
+ $gamesplist['counterstrike'][] = array('CS-Mod-Server', 'udp', '27011', '27011', 'both');
+ $gamesplist['counterstrike'][] = array('CS-Chat', 'udp', '27012', '27012', 'both');
+ $gamesplist['counterstrike'][] = array('CS-HL-Serverport1', 'udp', '27013', '27013', 'both');
+ $gamesplist['counterstrike'][] = array('CS-HL-Serverport2', 'udp', '27014', '27014', 'both');
+ $gamesplist['counterstrike'][] = array('CS-HL-Serverport', 'udp', '27015', '27015', 'both');
+
+$gamesplist['crysis2'] = array();
+ /* Crysis 2 */
+ $gamesplist['crysis2'][] = array('Crysis2', 'udp', '64100', '64100', 'both');
+
+$gamesplist['crysis3'] = array();
+ /* Crysis 3 */
+ $gamesplist['crysis3'][] = array('Crysis3-TCP-1', 'tcp', '9988', '9988', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-TCP-2', 'tcp', '17502', '17502', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-TCP-3', 'tcp', '25650', '25780', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-TCP-4', 'tcp', '42127', '42127', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-TCP-5', 'tcp', '64100', '64110', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-UDP-1', 'udp', '3659', '3659', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-UDP-2', 'udp', '10000', '10100', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-UDP-3', 'udp', '25650', '25780', 'both');
+ $gamesplist['crysis3'][] = array('Crysis3-UDP-4', 'udp', '64100', '64110', 'both');
+
+$gamesplist['deadspace2'] = array();
+ /* Dead Space 2 */
+ $gamesplist['deadspace2'][] = array('DeadSpace2-TCP-1', 'tcp', '28910', '28910', 'both');
+ $gamesplist['deadspace2'][] = array('DeadSpace2-TCP-2', 'tcp', '29900', '29901', 'both');
+ $gamesplist['deadspace2'][] = array('DeadSpace2-UDP-1', 'udp', '8088', '28088', 'both');
+
+$gamesplist['deadspace3'] = array();
+ /* Dead Space 3 */
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-1', 'tcp', '1024', '1124', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-2', 'tcp', '9960', '9969', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-3', 'tcp', '18000', '18000', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-4', 'tcp', '18120', '18120', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-5', 'tcp', '18060', '18060', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-6', 'tcp', '27900', '27900', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-7', 'tcp', '28910', '28910', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-TCP-8', 'tcp', '29900', '29900', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-UDP-1', 'udp', '1024', '1124', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-UDP-2', 'udp', '18000', '18000', 'both');
+ $gamesplist['deadspace3'][] = array('DeadSpace3-UDP-3', 'udp', '29900', '29900', 'both');
+
+$gamesplist['deltaforce'] = array();
+ /* delta force */
+ $gamesplist['deltaforce'][] = array('Delta1', 'udp', '17478', '17488', 'both');
+
+$gamesplist['dirt3'] = array();
+ /* ARMA 2 */
+ $gamesplist['dirt3'][] = array('Dirt3-1', 'tcp', '2300', '2400', 'both');
+ $gamesplist['dirt3'][] = array('Dirt3-2', 'udp', '2300', '2400', 'both');
+ $gamesplist['dirt3'][] = array('Dirt3-3', 'udp', '6073', '6073', 'both');
+ $gamesplist['dirt3'][] = array('Dirt3-4', 'tcp', '47624', '47624', 'both');
+
+$gamesplist['doom3'] = array();
+ /* doom3 */
+ $gamesplist['doom3'][] = array('DOOM3-1', 'udp', '27650', '27650', 'both');
+ $gamesplist['doom3'][] = array('DOOM3-2', 'udp', '27666', '27666', 'both');
+
+$gamesplist['dragonage2'] = array();
+ /* Dragon Age 2 */
+ $gamesplist['dragonage2'][] = array('DragonAge2-TCP-1', 'tcp', '8000', '8000', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-TCP-2', 'tcp', '12025', '12025', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-TCP-3', 'tcp', '15101', '15325', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-TCP-4', 'tcp', '18081', '18081', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-TCP-5', 'tcp', '42127', '42127', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-UDP-1', 'udp', '1900', '1900', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-UDP-2', 'udp', '5355', '5355', 'both');
+ $gamesplist['dragonage2'][] = array('DragonAge2-UDP-3', 'udp', '8001', '8001', 'both');
+
+$gamesplist['empireearth'] = array();
+ /* empire earth */
+ $gamesplist['empireearth'][] = array('EmpireEarth-1', 'tcp', '33335', '33336', 'both');
+ $gamesplist['empireearth'][] = array('EmpireEarth-2', 'udp', '33334', '33334', 'both');
+
+$gamesplist['eveonline'] = array();
+ /* EVE Online */
+ $gamesplist['eveonline'][] = array('EVEOnline-tcp', 'tcp', '26000', '26000', 'both');
+ $gamesplist['eveonline'][] = array('EVEOnline-udp', 'udp', '26000', '26000', 'both');
+ $gamesplist['eveonline'][] = array('EVEOnline-alternate-tcp', 'tcp', '3724', '3724', 'both');
+ $gamesplist['eveonline'][] = array('EVEOnline-alternate-udp', 'udp', '3724', '3724', 'both');
+
+$gamesplist['everquest'] = array();
+ /* everquest */
+ $gamesplist['everquest'][] = array('Everquest-1', 'tcp', '1024', '6000', 'both');
+ $gamesplist['everquest'][] = array('Everquest-2', 'tcp', '7000', '7000', 'both');
+ $gamesplist['everquest'][] = array('Everquest-3', 'udp', '1024', '6000', 'both');
+ $gamesplist['everquest'][] = array('Everquest-4', 'udp', '7000', '7000', 'both');
+
+$gamesplist['everquest2'] = array();
+ /* everquest2 */
+ $gamesplist['everquest2'][] = array('Everquest2-1', 'tcp', '7000', '7000', 'both');
+ $gamesplist['everquest2'][] = array('Everquest2-2', 'udp', '3016', '3021', 'both');
+ $gamesplist['everquest2'][] = array('Everquest2-3', 'udp', '9100', '9100', 'both');
+ $gamesplist['everquest2'][] = array('Everquest2-4', 'udp', '9700', '9703', 'both');
+ $gamesplist['everquest2'][] = array('Everquest2-5', 'udp', '32800', '33000', 'both');
+
+$gamesplist['farcry'] = array();
+ /* far cry */
+ $gamesplist['farcry'][] = array('FarCry-1', 'tcp', '49001', '49002', 'both');
+ $gamesplist['farcry'][] = array('FarCry-2', 'udp', '49001', '49002', 'both');
+
+$gamesplist['farcry2'] = array();
+ /* FarCry 2*/
+ $gamesplist['farcry2'][] = array('FarCry2-tcp', 'tcp', '9000', '9004', 'both');
+ $gamesplist['farcry2'][] = array('FarCry2-udp', 'udp', '9000', '9004', 'both');
+
+$gamesplist['farcry3'] = array();
+ /* FarCry 3*/
+ $gamesplist['farcry3'][] = array('FarCry3-game', 'udp', '9000', '9000', 'both');
+ $gamesplist['farcry3'][] = array('FarCry3-punkbuster', 'udp', '10009', '10009', 'both');
+
+$gamesplist['gunzonline'] = array();
+ /* GunZ Online */
+ $gamesplist['gunzonline'][] = array('GunZOnline', 'udp', '7700', '7700', 'both');
+
+$gamesplist['halflife'] = array();
+ /* halflife */
+ $gamesplist['halflife'][] = array('HL-1', 'tcp', '27015', '27015', 'both');
+ $gamesplist['halflife'][] = array('HL-2', 'udp', '27650', '27650', 'both');
+ $gamesplist['halflife'][] = array('HL-3', 'udp', '27666', '27666', 'both');
+
+$gamesplist['leagueoflegends'] = array();
+ /* League of Legends */
+ $gamesplist['leagueoflegends'][] = array('LeagueofLegends-1', 'udp', '5000', '5500', 'both');
+ $gamesplist['leagueoflegends'][] = array('LeagueofLegends-2', 'tcp', '2099', '2099', 'both');
+ $gamesplist['leagueoflegends'][] = array('LeagueofLegends-3', 'tcp', '5222', '5223', 'both');
+
+$gamesplist['lineage2'] = array();
+ /* Lineage II */
+ $gamesplist['lineage2'][] = array('Lineage2-2009', 'tcp', '2009', '2009', 'both');
+ $gamesplist['lineage2'][] = array('Lineage2-2106', 'tcp', '2106', '2106', 'both');
+ $gamesplist['lineage2'][] = array('Lineage2-7777', 'tcp', '7777', '7777', 'both');
+
+$gamesplist['masseffect3'] = array();
+ /* MassEffect 3 */
+ $gamesplist['masseffect3'][] = array('MassEffect3-UDP-1', 'udp', '5659', '5659', 'both');
+ $gamesplist['masseffect3'][] = array('MassEffect3-UDP-1', 'udp', '6000', '6000', 'both');
+
+$gamesplist['mechwarrioronline'] = array();
+ /* MechWarrior: Online */
+ $gamesplist['mechwarrioronline'][] = array('MechWarriorOnline-tcp1', 'tcp', '45461', '45461', 'both');
+ $gamesplist['mechwarrioronline'][] = array('MechWarriorOnline-tcp2', 'tcp', '45464', '45464', 'both');
+ $gamesplist['mechwarrioronline'][] = array('MechWarriorOnline-game', 'udp', '21000', '30000', 'both'); // 9000 ports
+
+$gamesplist['minecraft'] = array();
+ /* Minecraft */
+ $gamesplist['minecraft'][] = array('Minecraft-tcp', 'tcp', '25565', '25565', 'both');
+ $gamesplist['minecraft'][] = array('Minecraft-udp', 'udp', '25565', '25565', 'both');
+
+$gamesplist['operationflashpoint-dr'] = array();
+ /* Operation Flashpoint: Dragon Rising */
+ $gamesplist['operationflashpoint-dr'][] = array('OperationFlashpoint-DR', 'udp', '9105', '9105', 'both');
+
+$gamesplist['planetside'] = array();
+ /* PlanetSide */
+ $gamesplist['planetside'][] = array('PlanetSide', 'tcp', '7000', '7000', 'both');
+ $gamesplist['planetside'][] = array('PlanetSide', 'tcp', '7080', '7080', 'both');
+ $gamesplist['planetside'][] = array('PlanetSide2', 'udp', '3016', '3021', 'both');
+ $gamesplist['planetside'][] = array('PlanetSide2', 'udp', '45000', '45010', 'both');
+ $gamesplist['planetside'][] = array('PlanetSide2', 'udp', '30000', '30500', 'both');
+
+$gamesplist['planetside2'] = array();
+ /* PlanetSide 2 */
+ $gamesplist['planetside2'][] = array('PlanetSide2-game', 'udp', '20040', '20199', 'both');
+ $gamesplist['planetside2'][] = array('PlanetSide2-voice', 'udp', '5062', '5062', 'both');
+
+
+$gamesplist['quakeiii'] = array();
+ /* quake3 */
+ $gamesplist['quakeiii'][] = array('Quake3', 'udp', '27910', '27919', 'both');
+
+$gamesplist['quakeiv'] = array();
+ /* quake4 */
+ $gamesplist['quakeiv'][] = array('QuakeIV-server-udp', 'udp', '27650', '27650', 'both');
+ $gamesplist['quakeiv'][] = array('QuakeIV-server-tcp', 'tcp', '27650', '27650', 'both');
+ $gamesplist['quakeiv'][] = array('QuakeIV-client-udp', 'udp', '28004', '28004', 'both');
+ $gamesplist['quakeiv'][] = array('QuakeIV-client-tcp', 'tcp', '28004', '28004', 'both');
+
+$gamesplist['starwarstor'] = array();
+ /* quake3 */
+ $gamesplist['starwarstor'][] = array('StarWarsTOR-1', 'tcp', '8995', '8995', 'both');
+ $gamesplist['starwarstor'][] = array('StarWarsTOR-2', 'tcp', '12000', '12999', 'both');
+ $gamesplist['starwarstor'][] = array('StarWarsTOR-2', 'tcp', '20000', '30000', 'both');
+
+$gamesplist['tigerwoods2004ps2'] = array();
+ /* tiger woods 2004 ps2 */
+ $gamesplist['tigerwoods2004ps2'][] = array('TigerWoods2004-Player', 'udp', '3658', '3658', 'both');
+ $gamesplist['tigerwoods2004ps2'][] = array('TigerWoods2004-Player2', 'udp', '6000', '6000', 'both');
+ $gamesplist['tigerwoods2004ps2'][] = array('TigerWoods2004-EA', 'tcp', '10300', '10301', 'both');
+
+$gamesplist['tribesascend'] = array();
+ /* Tribes Ascend */
+ $gamesplist['tribesascend'][] = array('TribesAscend-tcp', 'tcp', '9000', '9001', 'both');
+ $gamesplist['tribesascend'][] = array('TribesAscend-udp', 'udp', '9002', '9999', 'both');
+
+$gamesplist['unrealtournament'] = array();
+ /* Unreal Tournament */
+ $gamesplist['unrealtournament'][] = array('UT-game-udp', 'udp', '7777', '7787', 'both');
+ $gamesplist['unrealtournament'][] = array('UT-game-tcp', 'tcp', '7777', '7787', 'both');
+ $gamesplist['unrealtournament'][] = array('UT-voice', 'udp', '3783', '3783', 'both');
+
+$gamesplist['wolfet'] = array();
+ /* wolfenstein enemy territory */
+ $gamesplist['wolfet'][] = array('WolfET-1', 'tcp', '27960', '27960', 'both');
+
+$gamesplist['wow'] = array();
+ /* World of Warcraft */
+ $gamesplist['wow'][] = array('WoW', 'tcp', '3724', '3724', 'both');
+ $gamesplist['wow'][] = array('WoW-voice', 'udp', '1119', '1119', 'both');
+ $gamesplist['wow'][] = array('WoW-voice', 'udp', '3724', '3724', 'both');
+
+$voiplist = array();
+
+ /* asterisk server / same as vonage */
+$voiplist['Asterisk'] = array();
+ $voiplist['Asterisk'][] = array('Asterisk', 'udp', '5060', '5069', 'both');
+ $voiplist['Asterisk'][] = array('Asterisk', 'udp', '10000', '20000', 'both');
+
+ /* VoicePulse server */
+$voiplist['VoicePulse'] = array();
+ $voiplist['VoicePulse'][] = array('VoicePulse', 'udp', '16384', '16482', 'both');
+ $voiplist['VoicePulse'][] = array('VoicePulse', 'udp', '4569', '4569', 'both');
+
+ /* Panasonic Hybrid PBX */
+$voiplist['Panasonic'] = array();
+ $voiplist['Panasonic'][] = array('Panasonic1', 'udp', '8000', '8063', 'both');
+ $voiplist['Panasonic'][] = array('Panasonic2', 'udp', '9300', '9301', 'both');
+ $voiplist['Panasonic'][] = array('Panasonic3', 'udp', '2747', '2747', 'both');
+
+
+$p2plist = array();
+ /* To add p2p clients, push Descr,Protocol,Start,End,src/dest/both onto p2plist */
+ $p2plist['aimster'] = array();
+ $p2plist['aimster'][] = array('Aimster', 'tcp', '7668', '7668', 'both');
+ $p2plist['bittorrent'] = array();
+ $p2plist['bittorrent'][] = array('BitTorrent', 'tcp', '6881', '6999', 'both');
+ $p2plist['bittorrent'][] = array('BitTorrent', 'udp', '6881', '6999', 'both');
+ $p2plist['buddyshare'] = array();
+ $p2plist['buddyshare'][] = array('BuddyShare', 'tcp', '7788', '7788', 'both');
+ $p2plist['cutemx'] = array();
+ $p2plist['cutemx'][] = array('CuteMX', 'tcp', '2340', '2340', 'both');
+ $p2plist['dc++'] = array();
+ $p2plist['dc++'][] = array('DC++', 'tcp', '1412', '1412', 'both');
+ $p2plist['dcc'] = array();
+ $p2plist['dcc'][] = array('dcc', 'tcp', '6666', '6668', 'both');
+ $p2plist['directconnect'] = array();
+ $p2plist['directconnect'][] = array('DirectConnect', 'tcp', '412', '412', 'both');
+ $p2plist['directfileexpress'] = array();
+ $p2plist['directfileexpress'][] = array('DirectFileExpress', 'tcp', '1044', '1045', 'both');
+ $p2plist['edonkey2000'] = array();
+ $p2plist['edonkey2000'][] = array('EDonkey2000', 'tcp', '4661', '4665', 'both');
+ $p2plist['fastTrack'] = array();
+ $p2plist['fastTrack'][] = array('FastTrack', 'tcp', '1214', '1214', 'both');
+ $p2plist['gnutella'] = array();
+ $p2plist['gnutella'][] = array('Gnutella-TCP', 'tcp', '6346', '6346', 'both');
+ $p2plist['gnutella'][] = array('Gnutella-UDP', 'udp', '6346', '6346', 'both');
+ $p2plist['grouper'] = array();
+ $p2plist['grouper'][] = array('grouper', 'tcp', '8038', '8039', 'both');
+ $p2plist['hotcomm'] = array();
+ $p2plist['hotcomm'][] = array('hotComm', 'tcp', '28864', '28865', 'both');
+ $p2plist['hotlineconnect'] = array();
+ $p2plist['hotlineconnect'][] = array('HotlineConnect', 'tcp', '5500', '5503', 'both');
+ $p2plist['imesh'] = array();
+ $p2plist['imesh'][] = array('iMesh', 'tcp', '4329', '4329', 'both');
+ $p2plist['napster'] = array();
+ $p2plist['napster'][] = array('Napster', 'tcp', '6699', '6701', 'both');
+ $p2plist['opennap'] = array();
+ $p2plist['opennap'][] = array('OpenNap', 'tcp', '8888', '8889', 'both');
+ $p2plist['scour'] = array();
+ $p2plist['scour'][] = array('Scour', 'tcp', '8311', '8311', 'both');
+ $p2plist['shareaza'] = array();
+ $p2plist['shareaza'][] = array('Shareaza', 'tcp', '6346', '6346', 'both');
+ $p2plist['songspy'] = array();
+ $p2plist['songspy'][] = array('SongSpy', 'tcp', '5190', '5190', 'both');
+ $p2plist['winmx'] = array();
+ $p2plist['winmx'][] = array('WinMX', 'tcp', '6699', '6699', 'both');
+
+
+
+$othersplist = array();
+ /* Unlike other areas we are posting the queue H or L or BLANK */
+
+ /* Remote Service / Terminal emulation */
+
+ $othersplist['appleremotedesktop'] = array();
+ /* apple remote desktop */
+ $othersplist['appleremotedesktop'][] = array('AppleRemoteDesktop1', 'tcp', '3283', '3283', 'both');
+ $othersplist['appleremotedesktop'][] = array('AppleRemoteDesktop2', 'tcp', '5900', '5900', 'both');
+ $othersplist['appleremotedesktop'][] = array('AppleRemoteDesktop3', 'udp', '3283', '3283', 'both');
+ $othersplist['appleremotedesktop'][] = array('AppleRemoteDesktop4', 'udp', '5900', '5900', 'both');
+
+ $othersplist['msrdp'] = array();
+ /* MSRDP */
+ $othersplist['msrdp'][] = array('MSRDP', 'tcp', '3389', '3389', 'both');
+
+ $othersplist['pcanywhere'] = array();
+ /* symantec pc anywhere */
+ $othersplist['pcanywhere'][] = array('PCAnywhere-1', 'tcp', '5631', '5631', 'both');
+ $othersplist['pcanywhere'][] = array('PCAnywhere-2', 'udp', '5632', '5632', 'both');
+
+ $othersplist['vnc'] = array();
+ /* virtual network control */
+ $othersplist['vnc'][] = array('VNC', 'tcp', '5900', '5930', 'both');
+
+ /* Messanger Clients */
+
+ $othersplist['aolinstantmessenger'] = array();
+ /* AIM */
+ $othersplist['aolinstantmessenger'][] = array('AIM', 'tcp', '5190', '5190', 'both');
+
+ $othersplist['facetime'] = array();
+ /* Facetime */
+ $othersplist['facetime'][] = array('Facetime-UDP-1', 'udp', '3478', '3479', 'both');
+ $othersplist['facetime'][] = array('Facetime-TCP-1', 'tcp', '16384', '16387', 'both');
+ $othersplist['facetime'][] = array('Facetime-TCP-2', 'tcp', '16393', '16402', 'both');
+
+ $othersplist['googlehangouts'] = array();
+ /* Google Hangouts */
+ $othersplist['googlehangouts'][] = array('GoogleHangouts-UDP', 'udp', '19302', '19309', 'both');
+ $othersplist['googlehangouts'][] = array('GoogleHangouts-TCP', 'tcp', '19305', '19309', 'both');
+
+ $othersplist['icq'] = array();
+ /* icq */
+ $othersplist['icq'][] = array('ICQ1', 'tcp', '5190', '5190', 'both');
+ $othersplist['icq'][] = array('ICQ2', 'udp', '5190', '5190', 'both');
+
+ $othersplist['irc'] = array();
+ /* internet relay chat */
+ $othersplist['irc'][] = array('IRC', 'tcp', '6667', '6670', 'both');
+
+ $othersplist['jabber'] = array();
+ /* jabber */
+ $othersplist['jabber'][] = array('IRC', 'tcp', '5222', '5222', 'both');
+ $othersplist['jabber'][] = array('IRC', 'tcp', '5223', '5223', 'both');
+ $othersplist['jabber'][] = array('IRC', 'tcp', '5269', '5269', 'both');
+
+ $othersplist['msnmessenger'] = array();
+ /* msn messenger */
+ $othersplist['msnmessenger'][] = array('MSN1', 'tcp', '1863', '1863', 'both');
+ $othersplist['msnmessenger'][] = array('MSN2', 'tcp', '6891', '6900', 'both');
+ $othersplist['msnmessenger'][] = array('MSN3', 'tcp', '6901', '6901', 'both');
+ $othersplist['msnmessenger'][] = array('MSN4', 'udp', '6901', '6901', 'both');
+
+ $othersplist['teamspeak'] = array();
+ /* teamspeak */
+ $othersplist['teamspeak'][] = array('TeamSpeak-1', 'tcp', '14534', '14534', 'both');
+ $othersplist['teamspeak'][] = array('TeamSpeak-2', 'tcp', '51234', '51234', 'both');
+ $othersplist['teamspeak'][] = array('TeamSpeak-3', 'udp', '8767', '8768', 'both');
+
+ $othersplist['teamspeak3'] = array();
+ /* teamspeak 3 */
+ $othersplist['teamspeak3'][] = array('TeamSpeak3-FileTransfer', 'tcp', '30033', '30033', 'both');
+ $othersplist['teamspeak3'][] = array('TeamSpeak3-ServerQuery', 'tcp', '10011', '10011', 'both');
+ $othersplist['teamspeak3'][] = array('TeamSpeak3-Voice', 'udp', '9987', '9987', 'both');
+ $othersplist['teamspeak3'][] = array('TeamSpeak3-TSDNS', 'tcp', '41144', '41144', 'both');
+
+ $othersplist['ventrilo'] = array();
+ /* ventrilo */
+ $othersplist['ventrilo'][] = array('Ventrilo-TCP', 'tcp', '3784', '3784', 'both');
+ $othersplist['ventrilo'][] = array('Ventrilo-UDP', 'udp', '3784', '3784', 'both');
+ $othersplist['ventrilo'][] = array('Ventrilo-Voice', 'udp', '6100', '6100', 'both');
+
+ /* VPN */
+
+ $othersplist['pptp'] = array();
+ /* PPTP */
+ $othersplist['pptp'][] = array('PPTP', 'tcp', '1723', '1723', 'both');
+ $othersplist['pptp'][] = array('PPTPGRE', 'gre', '', '', 'both');
+
+ $othersplist['ipsec'] = array();
+ /* IPSEC */
+ $othersplist['ipsec'][] = array('IPSEC', 'udp', '500', '500', 'both');
+ $othersplist['ipsec'][] = array('IPSEC', 'ah', '', '', 'both');
+ $othersplist['ipsec'][] = array('IPSEC', 'esp', '', '', 'both');
+
+ /* Multimedia/Streaming */
+
+ $othersplist['itunesradio'] = array();
+ /* Apple iTunes Radio Stream */
+ $othersplist['itunesradio'][] = array('iTunesRadio', 'tcp', '42000', '42999', 'both');
+
+ $othersplist['streamingmp3'] = array();
+ /* streaming mp3 media aka shoutcast */
+ $othersplist['streamingmp3'][] = array('STREAMINGMP3', 'tcp', '8000', '8100', 'both');
+
+ $othersplist['rtsp'] = array();
+ /* realtime streaming protocol */
+ $othersplist['rtsp'][] = array('RTSP1', 'tcp', '554', '554', 'both');
+
+ $othersplist['rtmp'] = array();
+ /* Real-Time Messaging Protocol */
+ $othersplist['rtmp'][] = array('RTMP', 'tcp', '1935', '1935', 'both');
+
+ /* Web */
+
+ $othersplist['http'] = array();
+ /* HTTP aka Web Traffic */
+ $othersplist['http'][] = array('HTTP', 'tcp', '80', '80', 'both');
+ $othersplist['http'][] = array('HTTPS', 'tcp', '443', '443', 'both');
+
+ /* Mail */
+
+ $othersplist['imap'] = array();
+ /* IMAP */
+ $othersplist['imap'][] = array('IMAP', 'tcp', '143', '143', 'both');
+ $othersplist['imap'][] = array('IMAP-Secure', 'tcp', '993', '993', 'both');
+
+ $othersplist['lotusnotes'] = array();
+ /* lotus notes */
+ $othersplist['lotusnotes'][] = array('LotusNotes1', 'tcp', '1352', '1352', 'both');
+ $othersplist['lotusnotes'][] = array('LotusNotes2', 'udp', '1352', '1352', 'both');
+
+ $othersplist['pop3'] = array();
+ /* Post Office Protocol - POP3 */
+ $othersplist['pop3'][] = array('POP3', 'tcp', '110', '110', 'both');
+ $othersplist['pop3'][] = array('POP3-Secure', 'tcp', '995', '995', 'both');
+
+ $othersplist['smtp'] = array();
+ /* SMTP */
+ $othersplist['smtp'][] = array('SMTP', 'tcp', '25', '25', 'both');
+ $othersplist['smtp'][] = array('SMTP-Secure-1', 'tcp', '465', '465', 'both');
+ $othersplist['smtp'][] = array('SMTP-Secure-2', 'tcp', '587', '587', 'both');
+
+ /* Game Downloader */
+
+ //NOTE: Battle.net-Downloader runs on this port range. Don't want that up with the game que.
+ $othersplist['battlenetdownloader'] = array();
+ $othersplist['battlenetdownloader'][] = array('Battle.NET-Downloader', 'tcp', '6881', '6999', 'both');
+
+ //NOTE: steam downloads, probably don't want this in the game que
+ $othersplist['steamdownloader'] = array();
+ $othersplist['steamdownloader'][] = array('Steam-Downloader', 'tcp', '27014', '27050', 'both');
+
+ /* Miscellaneous */
+
+ $othersplist['apns'] = array();
+ /* Apple Push Notification Service */
+ $othersplist['apns'][] = array('APNS', 'tcp', '5223', '5223', 'both');
+ $othersplist['apns'][] = array('APNS', 'tcp', '2195', '2196', 'both');
+
+ $othersplist['applemobilesync'] = array();
+ /* Apple Mobile Sync */
+ $othersplist['applemobilesync'][] = array('AppleMobileSync', 'tcp', '2336', '2336', 'both');
+
+ $othersplist['crashplan'] = array();
+ /* crashplan */
+ $othersplist['crashplan'][] = array('CrashPlan-1', 'tcp', '4282', '4282', 'both');
+ $othersplist['crashplan'][] = array('CrashPlan-2', 'tcp', '4285', '4285', 'both');
+
+ $othersplist['cvsup'] = array();
+ /* cvs */
+ $othersplist['cvsup'][] = array('cvsup', 'tcp', '5999', '5999', 'both');
+
+ $othersplist['dns'] = array();
+ /* domain name system */
+ $othersplist['dns'][] = array('DNS1', 'tcp', '53', '53', 'both');
+ $othersplist['dns'][] = array('DNS2', 'udp', '53', '53', 'both');
+
+ $othersplist['git'] = array();
+ /* GIT */
+ $othersplist['git'][] = array('git', 'tcp', '9418', '9418', 'both');
+
+ $othersplist['hbci'] = array();
+ /* HBCI */
+ $othersplist['hbci'][] = array('HBCI', 'tcp', '3000', '3000', 'both');
+
+ $othersplist['icmp'] = array();
+ /* ICMP */
+ $othersplist['icmp'][] = array('ICMP', 'icmp', '', '', 'both');
+
+ $othersplist['mysqlserver'] = array();
+ /* mysql server */
+ $othersplist['mysqlserver'][] = array('MySQL1', 'tcp', '3306', '3306', 'both');
+
+ $othersplist['nntp'] = array();
+ /* nntp */
+ $othersplist['nntp'][] = array('NNTP1', 'tcp', '119', '119', 'both');
+ $othersplist['nntp'][] = array('NNTP2', 'udp', '119', '119', 'both');
+
+ $othersplist['slingbox'] = array();
+ /* slingbox */
+ $othersplist['slingbox'][] = array('Slingbox1', 'tcp', '5001', '5001', 'both');
+ $othersplist['slingbox'][] = array('Slingbox2', 'udp', '5001', '5001', 'both');
+
+ $othersplist['smb'] = array();
+ /* Microsoft SMB and friends */
+ $othersplist['smb'][] = array('SMB1', 'tcp', '445', '445', 'both');
+ $othersplist['smb'][] = array('SMB2', 'tcp', '137-139', '137-139', 'both');
+
+ $othersplist['snmp'] = array();
+ /* Simple network management protocol */
+ $othersplist['snmp'][] = array('SNMP', 'tcp', '161', '161', 'both');
+ $othersplist['snmp'][] = array('SNMP2', 'udp', '161', '161', 'both');
+
+ $othersplist['subversion'] = array();
+ /* subversion */
+ $othersplist['subversion'][] = array('subversion', 'tcp', '3690', '3690', 'both');
+
+?>
diff --git a/src/etc/inc/xmlparse.inc b/src/etc/inc/xmlparse.inc
new file mode 100644
index 0000000..08d9b19
--- /dev/null
+++ b/src/etc/inc/xmlparse.inc
@@ -0,0 +1,334 @@
+<?php
+/* $Id$ */
+/*
+ xmlparse.inc
+ functions to parse/dump configuration files in XML format
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* The following items will be treated as arrays in config.xml */
+function listtags() {
+ /*
+ * Please keep this list alpha sorted and no longer than 80 characters
+ * I know it's a pain, but it's a pain to find stuff too if it's not
+ */
+ $ret = array(
+ 'acls', 'alias', 'aliasurl', 'allowedip', 'allowedhostname', 'authserver',
+ 'bridged', 'build_port_path',
+ 'ca', 'cacert', 'cert', 'crl', 'clone', 'config', 'container', 'columnitem',
+ 'depends_on_package', 'disk', 'dnsserver', 'dnsupdate', 'domainoverrides', 'dyndns',
+ 'earlyshellcmd', 'element', 'encryption-algorithm-option',
+ 'field', 'fieldname',
+ 'gateway_item', 'gateway_group', 'gif', 'gre', 'group',
+ 'hash-algorithm-option', 'hosts', 'member', 'ifgroupentry', 'igmpentry', 'interface_array', 'item', 'key',
+ 'lagg', 'lbaction', 'lbpool', 'l7rules', 'lbprotocol',
+ 'member', 'menu', 'tab', 'mobilekey', 'monitor_type', 'mount',
+ 'npt', 'ntpserver',
+ 'onetoone', 'openvpn-server', 'openvpn-client', 'openvpn-csc', 'option',
+ 'package', 'passthrumac', 'phase1', 'phase2', 'ppp', 'pppoe', 'priv', 'proxyarpnet', 'pool',
+ 'qinqentry', 'queue',
+ 'pages', 'pipe', 'radnsserver', 'roll', 'route', 'row', 'rrddatafile', 'rule',
+ 'schedule', 'service', 'servernat', 'servers',
+ 'serversdisabled', 'shellcmd', 'staticmap', 'subqueue',
+ 'timerange', 'tunnel', 'user', 'vip', 'virtual_server', 'vlan',
+ 'winsserver', 'wolentry', 'widget'
+ );
+ return array_flip($ret);
+}
+
+/* Package XML tags that should be treated as a list not as a traditional array */
+function listtags_pkg() {
+ $ret = array('build_port_path', 'depends_on_package', 'onetoone', 'queue', 'rule', 'servernat', 'alias', 'additional_files_needed', 'tab', 'template', 'menu', 'rowhelperfield', 'service', 'step', 'package', 'columnitem', 'option', 'item', 'field', 'package', 'file');
+
+ return array_flip($ret);
+}
+
+function startElement($parser, $name, $attrs) {
+ global $parsedcfg, $depth, $curpath, $havedata, $listtags;
+
+ array_push($curpath, strtolower($name));
+
+ $ptr =& $parsedcfg;
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ }
+
+ /* is it an element that belongs to a list? */
+ if (isset($listtags[strtolower($name)])) {
+
+ /* is there an array already? */
+ if (!is_array($ptr)) {
+ /* make an array */
+ $ptr = array();
+ }
+
+ array_push($curpath, count($ptr));
+
+ } else if (isset($ptr)) {
+ /* multiple entries not allowed for this element, bail out */
+ die(sprintf(gettext('XML error: %1$s at line %2$d cannot occur more than once') . "\n",
+ $name,
+ xml_get_current_line_number($parser)));
+ }
+
+ $depth++;
+ $havedata = $depth;
+}
+
+function endElement($parser, $name) {
+ global $depth, $curpath, $parsedcfg, $havedata, $listtags;
+
+ if ($havedata == $depth) {
+ $ptr =& $parsedcfg;
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ }
+ $ptr = "";
+ }
+
+ array_pop($curpath);
+
+ if (isset($listtags[strtolower($name)])) {
+ array_pop($curpath);
+ }
+
+ $depth--;
+}
+
+function cData($parser, $data) {
+ global $depth, $curpath, $parsedcfg, $havedata;
+
+ $data = trim($data, "\t\n\r");
+
+ if ($data != "") {
+ $ptr =& $parsedcfg;
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ }
+
+ if (is_string($ptr)) {
+ $ptr .= html_entity_decode($data);
+ } else {
+ if (trim($data, " ") != "") {
+ $ptr = html_entity_decode($data);
+ $havedata++;
+ }
+ }
+ }
+}
+
+function parse_xml_config($cffile, $rootobj, $isstring = "false") {
+ global $listtags;
+ $listtags = listtags();
+ if (isset($GLOBALS['custom_listtags'])) {
+ foreach ($GLOBALS['custom_listtags'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return parse_xml_config_raw($cffile, $rootobj, $isstring);
+}
+
+function parse_xml_config_pkg($cffile, $rootobj, $isstring = "false") {
+ global $listtags;
+ $listtags = listtags_pkg();
+ if (isset($GLOBALS['custom_listtags_pkg'])) {
+ foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ $cfg =parse_xml_config_raw($cffile, $rootobj, $isstring);
+ if ($cfg == -1) {
+ return array();
+ }
+
+ return $cfg;
+}
+
+function parse_xml_config_raw($cffile, $rootobj, $isstring = "false") {
+
+ global $depth, $curpath, $parsedcfg, $havedata, $listtags;
+ $parsedcfg = array();
+ $curpath = array();
+ $depth = 0;
+ $havedata = 0;
+
+ $xml_parser = xml_parser_create();
+
+ xml_set_element_handler($xml_parser, "startElement", "endElement");
+ xml_set_character_data_handler($xml_parser, "cdata");
+ xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1);
+
+ if (!($fp = fopen($cffile, "r"))) {
+ log_error(gettext("Error: could not open XML input") . "\n");
+ return -1;
+ }
+
+ while ($data = fread($fp, 4096)) {
+ if (!xml_parse($xml_parser, $data, feof($fp))) {
+ log_error(sprintf(gettext('XML error: %1$s at line %2$d in %3$s') . "\n",
+ xml_error_string(xml_get_error_code($xml_parser)),
+ xml_get_current_line_number($xml_parser),
+ $cffile));
+ return -1;
+ }
+ }
+ xml_parser_free($xml_parser);
+
+ if ($rootobj) {
+ if (!is_array($rootobj)) {
+ $rootobj = array($rootobj);
+ }
+ foreach ($rootobj as $rootobj_name) {
+ if ($parsedcfg[$rootobj_name]) {
+ break;
+ }
+ }
+
+ if (!$parsedcfg[$rootobj_name]) {
+ log_error(sprintf(gettext("XML error: no %s object found!") . "\n", implode(" or ", $rootobj)));
+ return -1;
+ }
+ return $parsedcfg[$rootobj_name];
+ } else {
+ return $parsedcfg;
+ }
+}
+
+function dump_xml_config_sub($arr, $indent) {
+
+ global $listtags;
+
+ $xmlconfig = "";
+
+ foreach ($arr as $ent => $val) {
+ if (is_array($val)) {
+ /* is it just a list of multiple values? */
+ if (isset($listtags[strtolower($ent)])) {
+ foreach ($val as $cval) {
+ if (is_array($cval)) {
+ if (empty($cval)) {
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "<$ent/>\n";
+ } else {
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "<$ent>\n";
+ $xmlconfig .= dump_xml_config_sub($cval, $indent + 1);
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "</$ent>\n";
+ }
+ } else {
+ if ($cval === false) {
+ continue;
+ }
+ $xmlconfig .= str_repeat("\t", $indent);
+ if ((is_bool($cval) && $cval == true) || ($cval === "")) {
+ $xmlconfig .= "<$ent/>\n";
+ } else if ((substr($ent, 0, 5) == "descr") ||
+ (substr($ent, 0, 6) == "detail") ||
+ (substr($ent, 0, 12) == "login_banner") ||
+ (substr($ent, 0, 9) == "ldap_attr") ||
+ (substr($ent, 0, 9) == "ldap_bind") ||
+ (substr($ent, 0, 11) == "ldap_basedn") ||
+ (substr($ent, 0, 18) == "ldap_authcn") ||
+ (substr($ent, 0, 19) == "ldap_extended_query")) {
+ $xmlconfig .= "<$ent><![CDATA[" . htmlentities($cval) . "]]></$ent>\n";
+ } else {
+ $xmlconfig .= "<$ent>" . htmlentities($cval) . "</$ent>\n";
+ }
+ }
+ }
+ } else if (empty($val)) {
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "<$ent/>\n";
+ } else {
+ /* it's an array */
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "<$ent>\n";
+ $xmlconfig .= dump_xml_config_sub($val, $indent + 1);
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "</$ent>\n";
+ }
+ } else {
+ if ((is_bool($val) && ($val == true)) || ($val === "")) {
+ $xmlconfig .= str_repeat("\t", $indent);
+ $xmlconfig .= "<$ent/>\n";
+ } else if (!is_bool($val)) {
+ $xmlconfig .= str_repeat("\t", $indent);
+ if ((substr($ent, 0, 5) == "descr") ||
+ (substr($ent, 0, 6) == "detail") ||
+ (substr($ent, 0, 12) == "login_banner") ||
+ (substr($ent, 0, 9) == "ldap_attr") ||
+ (substr($ent, 0, 9) == "ldap_bind") ||
+ (substr($ent, 0, 11) == "ldap_basedn") ||
+ (substr($ent, 0, 18) == "ldap_authcn") ||
+ (substr($ent, 0, 19) == "ldap_extended_query")) {
+ $xmlconfig .= "<$ent><![CDATA[" . htmlentities($val) . "]]></$ent>\n";
+ } else {
+ $xmlconfig .= "<$ent>" . htmlentities($val) . "</$ent>\n";
+ }
+ }
+ }
+ }
+
+ return $xmlconfig;
+}
+
+function dump_xml_config($arr, $rootobj) {
+ global $listtags;
+ $listtags = listtags();
+ if (isset($GLOBALS['custom_listtags'])) {
+ foreach ($GLOBALS['custom_listtags'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return dump_xml_config_raw($arr, $rootobj);
+}
+
+function dump_xml_config_pkg($arr, $rootobj) {
+ global $listtags;
+ $listtags = listtags_pkg();
+ if (isset($GLOBALS['custom_listtags_pkg'])) {
+ foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return dump_xml_config_raw($arr, $rootobj);
+}
+
+function dump_xml_config_raw($arr, $rootobj) {
+
+ $xmlconfig = "<?xml version=\"1.0\"?" . ">\n";
+ $xmlconfig .= "<$rootobj>\n";
+
+ $xmlconfig .= dump_xml_config_sub($arr, 1);
+
+ $xmlconfig .= "</$rootobj>\n";
+
+ return $xmlconfig;
+}
+
+?>
diff --git a/src/etc/inc/xmlparse_attr.inc b/src/etc/inc/xmlparse_attr.inc
new file mode 100644
index 0000000..ab90e98
--- /dev/null
+++ b/src/etc/inc/xmlparse_attr.inc
@@ -0,0 +1,237 @@
+<?php
+/* $Id$ */
+/*
+ xmlparse_attr.inc
+ functions to parse configuration files in XML format with attributes
+ Copyright (C) 2010 Erik Fonnesbeck
+ All rights reserved.
+
+ Based on xmlparse.inc, originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* The following items will be treated as arrays in regdomain.xml */
+function listtags_rd() {
+ $ret = explode(" ",
+ "band country flags freqband netband rd"
+ );
+ return $ret;
+}
+
+function startElement_attr($parser, $name, $attrs) {
+ global $parsedcfg, $depth, $curpath, $havedata, $listtags, $parsedattrs;
+
+ array_push($curpath, strtolower($name));
+
+ $ptr =& $parsedcfg;
+ if (!empty($attrs)) {
+ $attrptr =& $parsedattrs;
+ $writeattrs = true;
+ }
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ if (isset($writeattrs)) {
+ $attrptr =& $attrptr[$path];
+ }
+ }
+
+ /* is it an element that belongs to a list? */
+ if (in_array(strtolower($name), $listtags)) {
+
+ /* is there an array already? */
+ if (!is_array($ptr)) {
+ /* make an array */
+ $ptr = array();
+ }
+
+ array_push($curpath, count($ptr));
+
+ if (isset($writeattrs)) {
+ if (!is_array($attrptr)) {
+ $attrptr = array();
+ }
+ $attrptr[count($ptr)] = $attrs;
+ }
+
+ } else if (isset($ptr)) {
+ /* multiple entries not allowed for this element, bail out */
+ die(sprintf(gettext('XML error: %1$s at line %2$d cannot occur more than once') . "\n",
+ $name,
+ xml_get_current_line_number($parser)));
+ } else if (isset($writeattrs)) {
+ $attrptr = $attrs;
+ }
+
+ $depth++;
+ $havedata = $depth;
+}
+
+function endElement_attr($parser, $name) {
+ global $depth, $curpath, $parsedcfg, $havedata, $listtags;
+
+ if ($havedata == $depth) {
+ $ptr =& $parsedcfg;
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ }
+ $ptr = "";
+ }
+
+ array_pop($curpath);
+
+ if (in_array(strtolower($name), $listtags)) {
+ array_pop($curpath);
+ }
+
+ $depth--;
+}
+
+function cData_attr($parser, $data) {
+ global $depth, $curpath, $parsedcfg, $havedata;
+
+ $data = trim($data, "\t\n\r");
+
+ if ($data != "") {
+ $ptr =& $parsedcfg;
+ foreach ($curpath as $path) {
+ $ptr =& $ptr[$path];
+ }
+
+ if (is_string($ptr)) {
+ $ptr .= html_entity_decode($data);
+ } else {
+ if (trim($data, " ") != "") {
+ $ptr = html_entity_decode($data);
+ $havedata++;
+ }
+ }
+ }
+}
+
+function parse_xml_regdomain(&$rdattributes, $rdfile = '', $rootobj = 'regulatory-data') {
+ global $g, $listtags;
+
+ if (empty($rdfile)) {
+ $rdfile = $g['etc_path'] . '/regdomain.xml';
+ }
+ $listtags = listtags_rd();
+ $parsed_xml = array();
+
+ if (file_exists($g['tmp_path'] . '/regdomain.cache')) {
+ $parsed_xml = unserialize(file_get_contents($g['tmp_path'] . '/regdomain.cache'));
+ if (!empty($parsed_xml)) {
+ $rdmain = $parsed_xml['main'];
+ $rdattributes = $parsed_xml['attributes'];
+ }
+ }
+ if (empty($parsed_xml) && file_exists($g['etc_path'] . '/regdomain.xml')) {
+ $rdmain = parse_xml_config_raw_attr($rdfile, $rootobj, $rdattributes);
+
+ // unset parts that aren't used before making cache
+ foreach ($rdmain['regulatory-domains']['rd'] as $rdkey => $rdentry) {
+ if (isset($rdmain['regulatory-domains']['rd'][$rdkey]['netband'])) {
+ unset($rdmain['regulatory-domains']['rd'][$rdkey]['netband']);
+ }
+ if (isset($rdattributes['regulatory-domains']['rd'][$rdkey]['netband'])) {
+ unset($rdattributes['regulatory-domains']['rd'][$rdkey]['netband']);
+ }
+ }
+ if (isset($rdmain['shared-frequency-bands'])) {
+ unset($rdmain['shared-frequency-bands']);
+ }
+ if (isset($rdattributes['shared-frequency-bands'])) {
+ unset($rdattributes['shared-frequency-bands']);
+ }
+
+ $parsed_xml = array('main' => $rdmain, 'attributes' => $rdattributes);
+ $rdcache = fopen($g['tmp_path'] . '/regdomain.cache', "w");
+ fwrite($rdcache, serialize($parsed_xml));
+ fclose($rdcache);
+ }
+
+ return $rdmain;
+}
+
+function parse_xml_config_raw_attr($cffile, $rootobj, &$parsed_attributes, $isstring = "false") {
+
+ global $depth, $curpath, $parsedcfg, $havedata, $listtags, $parsedattrs;
+ $parsedcfg = array();
+ $curpath = array();
+ $depth = 0;
+ $havedata = 0;
+
+ if (isset($parsed_attributes)) {
+ $parsedattrs = array();
+ }
+
+ $xml_parser = xml_parser_create();
+
+ xml_set_element_handler($xml_parser, "startElement_attr", "endElement_attr");
+ xml_set_character_data_handler($xml_parser, "cData_attr");
+ xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1);
+
+ if (!($fp = fopen($cffile, "r"))) {
+ log_error(gettext("Error: could not open XML input") . "\n");
+ if (isset($parsed_attributes)) {
+ $parsed_attributes = array();
+ unset($parsedattrs);
+ }
+ return -1;
+ }
+
+ while ($data = fread($fp, 4096)) {
+ if (!xml_parse($xml_parser, $data, feof($fp))) {
+ log_error(sprintf(gettext('XML error: %1$s at line %2$d') . "\n",
+ xml_error_string(xml_get_error_code($xml_parser)),
+ xml_get_current_line_number($xml_parser)));
+ if (isset($parsed_attributes)) {
+ $parsed_attributes = array();
+ unset($parsedattrs);
+ }
+ return -1;
+ }
+ }
+ xml_parser_free($xml_parser);
+
+ if (!$parsedcfg[$rootobj]) {
+ log_error(sprintf(gettext("XML error: no %s object found!") . "\n", $rootobj));
+ if (isset($parsed_attributes)) {
+ $parsed_attributes = array();
+ unset($parsedattrs);
+ }
+ return -1;
+ }
+
+ if (isset($parsed_attributes)) {
+ if ($parsedattrs[$rootobj]) {
+ $parsed_attributes = $parsedattrs[$rootobj];
+ }
+ unset($parsedattrs);
+ }
+
+ return $parsedcfg[$rootobj];
+}
+
+?>
diff --git a/src/etc/inc/xmlreader.inc b/src/etc/inc/xmlreader.inc
new file mode 100644
index 0000000..960acb1
--- /dev/null
+++ b/src/etc/inc/xmlreader.inc
@@ -0,0 +1,277 @@
+<?php
+/* $Id$ */
+/*
+ xmlreader.inc
+ functions to parse/dump configuration files in XML format
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_MODULE: utils
+*/
+
+/* The following items will be treated as arrays in config.xml */
+function listtags() {
+ /*
+ * Please keep this list alpha sorted and no longer than 80 characters
+ * I know it's a pain, but it's a pain to find stuff too if it's not
+ */
+ $ret = array(
+ 'acls', 'alias', 'aliasurl', 'allowedip', 'allowedhostname', 'authserver',
+ 'bridged', 'build_port_path',
+ 'ca', 'cacert', 'cert', 'crl', 'clone', 'config', 'container', 'columnitem',
+ 'depends_on_package', 'disk', 'dnsserver', 'dnsupdate', 'domainoverrides', 'dyndns',
+ 'earlyshellcmd', 'element', 'encryption-algorithm-option',
+ 'field', 'fieldname',
+ 'gateway_item', 'gateway_group', 'gif', 'gre', 'group',
+ 'hash-algorithm-option', 'hosts', 'member', 'ifgroupentry', 'igmpentry', 'interface_array', 'item', 'key',
+ 'lagg', 'lbaction', 'lbpool', 'l7rules', 'lbprotocol',
+ 'member', 'menu', 'tab', 'mobilekey', 'monitor_type', 'mount',
+ 'npt', 'ntpserver',
+ 'onetoone', 'openvpn-server', 'openvpn-client', 'openvpn-csc', 'option',
+ 'package', 'passthrumac', 'phase1', 'phase2', 'ppp', 'pppoe', 'priv', 'proxyarpnet', 'pool',
+ 'qinqentry', 'queue',
+ 'pages', 'pipe', 'radnsserver', 'roll', 'route', 'row', 'rrddatafile', 'rule',
+ 'schedule', 'service', 'servernat', 'servers',
+ 'serversdisabled', 'shellcmd', 'staticmap', 'subqueue',
+ 'timerange', 'tunnel', 'user', 'vip', 'virtual_server', 'vlan',
+ 'winsserver', 'wolentry', 'widget'
+ );
+ return array_flip($ret);
+}
+
+/* Package XML tags that should be treat as a list not as a traditional array */
+function listtags_pkg() {
+ $ret = array('depends_on_package', 'onetoone', 'queue', 'rule', 'servernat', 'alias', 'additional_files_needed', 'tab', 'template', 'menu', 'rowhelperfield', 'service', 'step', 'package', 'columnitem', 'option', 'item', 'field', 'package', 'file');
+
+ return array_flip($ret);
+}
+
+function add_elements(&$cfgarray, &$parser) {
+ global $listtags;
+
+ while ($parser->read()) {
+ switch ($parser->nodeType) {
+ case XMLReader::WHITESPACE:
+ case XMLReader::SIGNIFICANT_WHITESPACE:
+ break;
+ case XMLReader::ELEMENT:
+ if (isset($listtags[strtolower($parser->name)])) {
+ $cfgref =& $cfgarray[$parser->name][count($cfgarray[$parser->name])];
+ if (!$parser->isEmptyElement) {
+ add_elements($cfgref, $parser);
+ } else {
+ $cfgref = array();
+ }
+ } else {
+ if (isset($cfgarray[$parser->name]) && (!is_array($cfgarray[$parser->name]) || !isset($cfgarray[$parser->name][0]))) {
+ $nodebkp = $cfgarray[$parser->name];
+ $cfgarray[$parser->name] = array();
+ $cfgarray[$parser->name][] = $nodebkp;
+ $cfgref =& $cfgarray[$parser->name][0];
+ unset($nodebkp);
+ } else {
+ $cfgref =& $cfgarray[$parser->name];
+ }
+
+ if ($parser->isEmptyElement) {
+ if (is_array($cfgref)) {
+ $cfgref[] = array();
+ } else {
+ $cfgref = "";
+ }
+ } else {
+ if (is_array($cfgref)) {
+ $cfgref =& $cfgarray[$parser->name][count($cfgarray[$parser->name])];
+ add_elements($cfgref, $parser);
+ } else {
+ add_elements($cfgref, $parser);
+ }
+ }
+ }
+
+ $i = 0;
+ while ($parser->moveToAttributeNo($i)) {
+ $cfgref[$parser->name] = $parser->value;
+ $i++;
+ }
+ break;
+ case XMLReader::TEXT:
+ case XMLReader::CDATA:
+ $cfgarray = $parser->value;
+ break;
+ case XMLReader::END_ELEMENT:
+ return;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+function parse_xml_config($cffile, $rootobj, $isstring = "false") {
+ global $listtags;
+
+ $listtags = listtags();
+ if (isset($GLOBALS['custom_listtags'])) {
+ foreach ($GLOBALS['custom_listtags'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+
+ return parse_xml_config_raw($cffile, $rootobj);
+}
+
+function parse_xml_config_pkg($cffile, $rootobj, $isstring = "false") {
+ global $listtags;
+
+ $listtags = listtags_pkg();
+ if (isset($GLOBALS['custom_listtags_pkg'])) {
+ foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return parse_xml_config_raw($cffile, $rootobj, $isstring);
+}
+
+function parse_xml_config_raw($cffile, $rootobj, $isstring = "false") {
+ global $listtags;
+
+ $parsedcfg = array();
+
+ $par = new XMLReader();
+ if ($par->open($cffile, "UTF-8", LIBXML_NOERROR | LIBXML_NOWARNING)) {
+ add_elements($parsedcfg, $par);
+ $par->close();
+ } else {
+ log_error(sprintf(gettext("Error returned while trying to parse %s"), $cffile));
+ }
+
+ if ($rootobj) {
+ if (!is_array($rootobj)) {
+ $rootobj = array($rootobj);
+ }
+ foreach ($rootobj as $rootobj_name) {
+ if ($parsedcfg[$rootobj_name]) {
+ break;
+ }
+ }
+
+ return $parsedcfg[$rootobj_name];
+ } else {
+ return $parsedcfg;
+ }
+}
+
+function dump_xml_config_sub(& $writer, $arr) {
+ global $listtags;
+
+ foreach ($arr as $ent => $val) {
+ if (is_array($val)) {
+ /* is it just a list of multiple values? */
+ if (isset($listtags[strtolower($ent)])) {
+ foreach ($val as $cval) {
+ if (is_array($cval)) {
+ if (empty($cval)) {
+ $writer->writeElement($ent);
+ } else {
+ $writer->startElement($ent);
+ dump_xml_config_sub($writer, $cval);
+ $writer->endElement();
+ }
+ } else {
+ if ($cval === false) {
+ continue;
+ }
+ if ((is_bool($val) && ($val == true)) || ($val === "")) {
+ $writer->writeElement($ent);
+ } else if (!is_bool($val)) {
+ $writer->writeElement($ent, $cval);
+ }
+ }
+ }
+ } else if (empty($val)) {
+ $writer->writeElement($ent);
+ } else {
+ /* it's an array */
+ $writer->startElement($ent);
+ dump_xml_config_sub($writer, $val);
+ $writer->endElement();
+ }
+ } else {
+ if ((is_bool($val) && ($val == true)) || ($val === "")) {
+ $writer->writeElement($ent);
+ } else if (!is_bool($val)) {
+ $writer->writeElement($ent, $val);
+ }
+ }
+ }
+}
+
+function dump_xml_config($arr, $rootobj) {
+ global $listtags;
+
+ $listtags = listtags();
+ if (isset($GLOBALS['custom_listtags'])) {
+ foreach ($GLOBALS['custom_listtags'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return dump_xml_config_raw($arr, $rootobj);
+}
+
+function dump_xml_config_pkg($arr, $rootobj) {
+ global $listtags;
+
+ $listtags = listtags_pkg();
+ if (isset($GLOBALS['custom_listtags_pkg'])) {
+ foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
+ $listtags[$tag] = $tag;
+ }
+ }
+ return dump_xml_config_raw($arr, $rootobj);
+}
+
+function dump_xml_config_raw($arr, $rootobj) {
+
+ $writer = new XMLWriter();
+ $writer->openMemory();
+ $writer->setIndent(true);
+ $writer->setIndentString("\t");
+ $writer->startDocument("1.0", "UTF-8");
+ $writer->startElement($rootobj);
+
+ dump_xml_config_sub($writer, $arr);
+
+ $writer->endElement();
+ $writer->endDocument();
+ $xmlconfig = $writer->outputMemory(true);
+
+ return $xmlconfig;
+}
+
+?>
diff --git a/src/etc/inc/xmlrpc.inc b/src/etc/inc/xmlrpc.inc
new file mode 100644
index 0000000..e96e783
--- /dev/null
+++ b/src/etc/inc/xmlrpc.inc
@@ -0,0 +1,148 @@
+<?php
+/*
+ $Id$
+
+ xmlrpc.inc
+ Copyright (C) 2005-2006 Colin Smith
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ pfSense_BUILDER_BINARIES:
+ pfSense_MODULE: utils
+*/
+
+require_once("auth.inc");
+require_once("xmlrpc_client.inc");
+
+/*
+ * xmlrpc_params_to_php: Convert params array passed from XMLRPC server into a PHP array and return it.
+ */
+function xmlrpc_params_to_php($params) {
+ $array = array();
+ for ($i = 0; $i < $params->getNumParams(); $i++) {
+ $value = $params->getParam($i);
+ $array[] = XML_RPC_decode($value);
+ }
+ return $array;
+}
+
+/*
+ * xmlrpc_value_to_php: Convert an XMLRPC value into a PHP scalar/array and return it.
+ */
+function xmlrpc_value_to_php($raw_value) {
+ /*
+ switch ($raw_value->kindOf()) {
+ case "scalar":
+ if ($raw_value->scalartyp() == "boolean") {
+ $return = (boolean) $raw_value->scalarval();
+ }
+ $return = $raw_value->scalarval();
+ break;
+ case "array":
+ $return = array();
+ for ($i = 0; $i < $raw_value->arraysize(); $i++) {
+ $value = $raw_value->arraymem($i);
+ $return[] = xmlrpc_value_to_php($value);
+ }
+ break;
+ case "struct":
+ $return = array();
+ for ($i = 0; $i < $raw_value->arraysize(); $i++) {
+ list($key, $value) = $raw_value->structeach();
+ $return[$key] = xmlrpc_value_to_php($value);
+ }
+ break;
+ }
+ */
+ return XML_RPC_decode($raw_value);
+}
+
+/*
+ * php_value_to_xmlrpc: Convert a PHP scalar or array into its XMLRPC equivalent.
+ */
+function php_value_to_xmlrpc($value, $force_array = false) {
+ $toreturn = XML_RPC_encode($value);
+ return $force_array ? array($toreturn) : $toreturn;
+ /*
+ if (gettype($value) == "array") {
+ $xmlrpc_type = "array";
+ $toreturn = array();
+ foreach ($value as $key => $val) {
+ if (is_string($key)) {
+ $xmlrpc_type = "struct";
+ }
+ $toreturn[$key] = php_value_to_xmlrpc($val);
+ }
+ return new XML_RPC_Value($toreturn, $xmlrpc_type);
+ } else {
+ if ($force_array == true) {
+ return new XML_RPC_Value(array(new XML_RPC_Value($value, gettype($value))), "array");
+ } else {
+ return new XML_RPC_Value($value, gettype($value));
+ }
+ }
+ */
+}
+
+/*
+ * xmlrpc_auth: Handle basic crypt() authentication of an XMLRPC request. This function assumes that
+ * $params[0] contains the local system's plaintext password and removes the password from
+ * the array before returning it.
+ */
+function xmlrpc_auth(&$params) {
+ global $config, $_SERVER;
+
+ /* XXX: Should teach caller to pass username and use it here. */
+ /* XXX: Should clarify from old behaviour what is in params[0] that differs from params['xmlrpcauth'] */
+ if (isset($config['system']['webgui']['authmode'])) {
+ $authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
+ if (authenticate_user("admin", $params[0], $authcfg) ||
+ authenticate_user("admin", $params[0])) {
+ array_shift($params);
+ unset($params['xmlrpcauth']);
+ return true;
+ } else if (!empty($params['xmlrpcauth']) && (authenticate_user("admin", $params['xmlrpcauth'], $authcfg) ||
+ authenticate_user("admin", $params['xmlrpcauth']))) {
+ array_shift($params);
+ unset($params['xmlrpcauth']);
+ return true;
+ }
+ } else if (authenticate_user("admin", $params[0])) {
+ array_shift($params);
+ unset($params['xmlrpcauth']);
+ return true;
+ } else if (!empty($params['xmlrpcauth']) && authenticate_user("admin", $params['xmlrpcauth'])) {
+ array_shift($params);
+ unset($params['xmlrpcauth']);
+ return true;
+ }
+
+ array_shift($params);
+ unset($params['xmlrpcauth']);
+ log_error("webConfigurator authentication error for 'admin' from {$_SERVER['REMOTE_ADDR']} during sync settings.");
+ return false;
+}
+
+?>
diff --git a/src/etc/inc/xmlrpc_client.inc b/src/etc/inc/xmlrpc_client.inc
new file mode 100644
index 0000000..fbbf977
--- /dev/null
+++ b/src/etc/inc/xmlrpc_client.inc
@@ -0,0 +1,2060 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP implementation of the XML-RPC protocol
+ *
+ * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
+ * It has support for HTTP transport, proxies and authentication.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version SVN: $Id: RPC.php 300961 2010-07-03 02:17:34Z danielc $
+ * @link http://pear.php.net/package/XML_RPC
+ */
+
+
+if (!function_exists('xml_parser_create')) {
+ include_once 'PEAR.inc';
+ PEAR::loadExtension('xml');
+}
+
+/**#@+
+ * Error constants
+ */
+/**
+ * Parameter values don't match parameter types
+ */
+define('XML_RPC_ERROR_INVALID_TYPE', 101);
+/**
+ * Parameter declared to be numeric but the values are not
+ */
+define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
+/**
+ * Communication error
+ */
+define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
+/**
+ * The array or struct has already been started
+ */
+define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+/**
+ * Incorrect parameters submitted
+ */
+define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
+/**
+ * Programming error by developer
+ */
+define('XML_RPC_ERROR_PROGRAMMING', 106);
+/**#@-*/
+
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_I4']
+ */
+$GLOBALS['XML_RPC_I4'] = 'i4';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Int']
+ */
+$GLOBALS['XML_RPC_Int'] = 'int';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Boolean']
+ */
+$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Double']
+ */
+$GLOBALS['XML_RPC_Double'] = 'double';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_String']
+ */
+$GLOBALS['XML_RPC_String'] = 'string';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_DateTime']
+ */
+$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Base64']
+ */
+$GLOBALS['XML_RPC_Base64'] = 'base64';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Array']
+ */
+$GLOBALS['XML_RPC_Array'] = 'array';
+
+/**
+ * Data types
+ * @global string $GLOBALS['XML_RPC_Struct']
+ */
+$GLOBALS['XML_RPC_Struct'] = 'struct';
+
+
+/**
+ * Data type meta-types
+ * @global array $GLOBALS['XML_RPC_Types']
+ */
+$GLOBALS['XML_RPC_Types'] = array(
+ $GLOBALS['XML_RPC_I4'] => 1,
+ $GLOBALS['XML_RPC_Int'] => 1,
+ $GLOBALS['XML_RPC_Boolean'] => 1,
+ $GLOBALS['XML_RPC_String'] => 1,
+ $GLOBALS['XML_RPC_Double'] => 1,
+ $GLOBALS['XML_RPC_DateTime'] => 1,
+ $GLOBALS['XML_RPC_Base64'] => 1,
+ $GLOBALS['XML_RPC_Array'] => 2,
+ $GLOBALS['XML_RPC_Struct'] => 3,
+);
+
+
+/**
+ * Error message numbers
+ * @global array $GLOBALS['XML_RPC_err']
+ */
+$GLOBALS['XML_RPC_err'] = array(
+ 'unknown_method' => 1,
+ 'invalid_return' => 2,
+ 'incorrect_params' => 3,
+ 'introspect_unknown' => 4,
+ 'http_error' => 5,
+ 'not_response_object' => 6,
+ 'invalid_request' => 7,
+);
+
+/**
+ * Error message strings
+ * @global array $GLOBALS['XML_RPC_str']
+ */
+$GLOBALS['XML_RPC_str'] = array(
+ 'unknown_method' => gettext("Unknown method"),
+ 'invalid_return' => gettext("Invalid return payload: enable debugging to examine incoming payload"),
+ 'incorrect_params' => gettext("Incorrect parameters passed to method"),
+ 'introspect_unknown' => gettext("Can't introspect: method unknown"),
+ 'http_error' => gettext("Didn't receive 200 OK from remote server."),
+ 'not_response_object' => gettext("The requested method didn't return an XML_RPC_Response object."),
+ 'invalid_request' => gettext("Invalid request payload"),
+);
+
+
+/**
+ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+ * @global string $GLOBALS['XML_RPC_defencoding']
+ */
+$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+
+/**
+ * User error codes start at 800
+ * @global int $GLOBALS['XML_RPC_erruser']
+ */
+$GLOBALS['XML_RPC_erruser'] = 800;
+
+/**
+ * XML parse error codes start at 100
+ * @global int $GLOBALS['XML_RPC_errxml']
+ */
+$GLOBALS['XML_RPC_errxml'] = 100;
+
+
+/**
+ * Compose backslashes for escaping regexp
+ * @global string $GLOBALS['XML_RPC_backslash']
+ */
+$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+
+
+/**
+ * Should we automatically base64 encode strings that contain characters
+ * which can cause PHP's SAX-based XML parser to break?
+ * @global boolean $GLOBALS['XML_RPC_auto_base64']
+ */
+$GLOBALS['XML_RPC_auto_base64'] = true;
+
+
+/**
+ * Valid parents of XML elements
+ * @global array $GLOBALS['XML_RPC_valid_parents']
+ */
+$GLOBALS['XML_RPC_valid_parents'] = array(
+ 'BOOLEAN' => array('VALUE'),
+ 'I4' => array('VALUE'),
+ 'INT' => array('VALUE'),
+ 'STRING' => array('VALUE'),
+ 'DOUBLE' => array('VALUE'),
+ 'DATETIME.ISO8601' => array('VALUE'),
+ 'BASE64' => array('VALUE'),
+ 'ARRAY' => array('VALUE'),
+ 'STRUCT' => array('VALUE'),
+ 'PARAM' => array('PARAMS'),
+ 'METHODNAME' => array('METHODCALL'),
+ 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
+ 'MEMBER' => array('STRUCT'),
+ 'NAME' => array('MEMBER'),
+ 'DATA' => array('ARRAY'),
+ 'FAULT' => array('METHODRESPONSE'),
+ 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
+);
+
+
+/**
+ * Stores state during parsing
+ *
+ * quick explanation of components:
+ * + ac = accumulates values
+ * + qt = decides if quotes are needed for evaluation
+ * + cm = denotes struct or array (comma needed)
+ * + isf = indicates a fault
+ * + lv = indicates "looking for a value": implements the logic
+ * to allow values with no types to be strings
+ * + params = stores parameters in method calls
+ * + method = stores method name
+ *
+ * @global array $GLOBALS['XML_RPC_xh']
+ */
+$GLOBALS['XML_RPC_xh'] = array();
+
+
+/**
+ * Start element handler for the XML parser
+ *
+ * @return void
+ */
+function XML_RPC_se($parser_resource, $name, $attrs)
+{
+ global $XML_RPC_xh, $XML_RPC_valid_parents;
+
+ $parser = (int) $parser_resource;
+
+ // if invalid xmlrpc already detected, skip all processing
+ if ($XML_RPC_xh[$parser]['isf'] >= 2) {
+ return;
+ }
+
+ // check for correct element nesting
+ // top level element can only be of 2 types
+ if (count($XML_RPC_xh[$parser]['stack']) == 0) {
+ if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
+ $XML_RPC_xh[$parser]['isf'] = 2;
+ $XML_RPC_xh[$parser]['isf_reason'] = gettext('missing top level xmlrpc element');
+ return;
+ }
+ } else {
+ // not top level element: see if parent is OK
+ if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
+ $name = preg_replace('@[^a-zA-Z0-9._-]@', '', $name);
+ $XML_RPC_xh[$parser]['isf'] = 2;
+ $XML_RPC_xh[$parser]['isf_reason'] = sprintf(gettext('xmlrpc element %1$s cannot be child of %2$s'), $name, $XML_RPC_xh[$parser]['stack'][0]);
+ return;
+ }
+ }
+
+ switch ($name) {
+ case 'STRUCT':
+ $XML_RPC_xh[$parser]['cm']++;
+
+ // turn quoting off
+ $XML_RPC_xh[$parser]['qt'] = 0;
+
+ $cur_val = array();
+ $cur_val['value'] = array();
+ $cur_val['members'] = 1;
+ array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
+ break;
+
+ case 'ARRAY':
+ $XML_RPC_xh[$parser]['cm']++;
+
+ // turn quoting off
+ $XML_RPC_xh[$parser]['qt'] = 0;
+
+ $cur_val = array();
+ $cur_val['value'] = array();
+ $cur_val['members'] = 0;
+ array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
+ break;
+
+ case 'NAME':
+ $XML_RPC_xh[$parser]['ac'] = '';
+ break;
+
+ case 'FAULT':
+ $XML_RPC_xh[$parser]['isf'] = 1;
+ break;
+
+ case 'PARAM':
+ $XML_RPC_xh[$parser]['valuestack'] = array();
+ break;
+
+ case 'VALUE':
+ $XML_RPC_xh[$parser]['lv'] = 1;
+ $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String'];
+ $XML_RPC_xh[$parser]['ac'] = '';
+ $XML_RPC_xh[$parser]['qt'] = 0;
+ // look for a value: if this is still 1 by the
+ // time we reach the first data segment then the type is string
+ // by implication and we need to add in a quote
+ break;
+
+ case 'I4':
+ case 'INT':
+ case 'STRING':
+ case 'BOOLEAN':
+ case 'DOUBLE':
+ case 'DATETIME.ISO8601':
+ case 'BASE64':
+ $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+
+ if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+ $XML_RPC_xh[$parser]['qt'] = 1;
+
+ if ($name == 'DATETIME.ISO8601') {
+ $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime'];
+ }
+
+ } elseif ($name == 'BASE64') {
+ $XML_RPC_xh[$parser]['qt'] = 2;
+ } else {
+ // No quoting is required here -- but
+ // at the end of the element we must check
+ // for data format errors.
+ $XML_RPC_xh[$parser]['qt'] = 0;
+ }
+ break;
+
+ case 'MEMBER':
+ $XML_RPC_xh[$parser]['ac'] = '';
+ break;
+
+ case 'DATA':
+ case 'METHODCALL':
+ case 'METHODNAME':
+ case 'METHODRESPONSE':
+ case 'PARAMS':
+ // valid elements that add little to processing
+ break;
+ }
+
+
+ // Save current element to stack
+ array_unshift($XML_RPC_xh[$parser]['stack'], $name);
+
+ if ($name != 'VALUE') {
+ $XML_RPC_xh[$parser]['lv'] = 0;
+ }
+}
+
+/**
+ * End element handler for the XML parser
+ *
+ * @return void
+ */
+function XML_RPC_ee($parser_resource, $name)
+{
+ global $XML_RPC_xh;
+
+ $parser = (int) $parser_resource;
+
+ if ($XML_RPC_xh[$parser]['isf'] >= 2) {
+ return;
+ }
+
+ // push this element from stack
+ // NB: if XML validates, correct opening/closing is guaranteed and
+ // we do not have to check for $name == $curr_elem.
+ // we also checked for proper nesting at start of elements...
+ $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
+
+ switch ($name) {
+ case 'STRUCT':
+ case 'ARRAY':
+ $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
+ $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
+ $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+ $XML_RPC_xh[$parser]['cm']--;
+ break;
+
+ case 'NAME':
+ $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
+ break;
+
+ case 'BOOLEAN':
+ // special case here: we translate boolean 1 or 0 into PHP
+ // constants true or false
+ if ($XML_RPC_xh[$parser]['ac'] == '1') {
+ $XML_RPC_xh[$parser]['ac'] = 'true';
+ } else {
+ $XML_RPC_xh[$parser]['ac'] = 'false';
+ }
+
+ $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+ // Drop through intentionally.
+
+ case 'I4':
+ case 'INT':
+ case 'STRING':
+ case 'DOUBLE':
+ case 'DATETIME.ISO8601':
+ case 'BASE64':
+ if ($XML_RPC_xh[$parser]['qt'] == 1) {
+ // we use double quotes rather than single so backslashification works OK
+ $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
+ } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+ $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
+ } elseif ($name == 'BOOLEAN') {
+ $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
+ } else {
+ // we have an I4, INT or a DOUBLE
+ // we must check that only 0123456789-.<space> are characters here
+ if (!preg_match("@^[+-]?[0123456789 \t\.]+$@", $XML_RPC_xh[$parser]['ac'])) {
+ XML_RPC_Base::raiseError(gettext('Non-numeric value received in INT or DOUBLE'),
+ XML_RPC_ERROR_NON_NUMERIC_FOUND);
+ $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
+ } else {
+ // it's ok, add it on
+ $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
+ }
+ }
+
+ $XML_RPC_xh[$parser]['ac'] = '';
+ $XML_RPC_xh[$parser]['qt'] = 0;
+ $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+ break;
+
+ case 'VALUE':
+ if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) {
+ if (strlen($XML_RPC_xh[$parser]['ac']) > 0) {
+ $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
+ } elseif ($XML_RPC_xh[$parser]['lv'] == 1) {
+ // The <value> element was empty.
+ $XML_RPC_xh[$parser]['value'] = '';
+ }
+ }
+
+ $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
+
+ $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
+ if (is_array($cur_val)) {
+ if ($cur_val['members']==0) {
+ $cur_val['value'][] = $temp;
+ } else {
+ $XML_RPC_xh[$parser]['value'] = $temp;
+ }
+ array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
+ } else {
+ $XML_RPC_xh[$parser]['value'] = $temp;
+ }
+ break;
+
+ case 'MEMBER':
+ $XML_RPC_xh[$parser]['ac'] = '';
+ $XML_RPC_xh[$parser]['qt'] = 0;
+
+ $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
+ if (is_array($cur_val)) {
+ if ($cur_val['members']==1) {
+ $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
+ }
+ array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
+ }
+ break;
+
+ case 'DATA':
+ $XML_RPC_xh[$parser]['ac'] = '';
+ $XML_RPC_xh[$parser]['qt'] = 0;
+ break;
+
+ case 'PARAM':
+ $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
+ break;
+
+ case 'METHODNAME':
+ case 'RPCMETHODNAME':
+ $XML_RPC_xh[$parser]['method'] = preg_replace("@^[\n\r\t ]+@", '',
+ $XML_RPC_xh[$parser]['ac']);
+ break;
+ }
+
+ // if it's a valid type name, set the type
+ if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) {
+ $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+ }
+}
+
+/**
+ * Character data handler for the XML parser
+ *
+ * @return void
+ */
+function XML_RPC_cd($parser_resource, $data)
+{
+ global $XML_RPC_xh, $XML_RPC_backslash;
+
+ $parser = (int) $parser_resource;
+
+ if ($XML_RPC_xh[$parser]['lv'] != 3) {
+ // "lookforvalue==3" means that we've found an entire value
+ // and should discard any further character data
+
+ if ($XML_RPC_xh[$parser]['lv'] == 1) {
+ // if we've found text and we're just in a <value> then
+ // turn quoting on, as this will be a string
+ $XML_RPC_xh[$parser]['qt'] = 1;
+ // and say we've found a value
+ $XML_RPC_xh[$parser]['lv'] = 2;
+ }
+
+ // replace characters that eval would
+ // do special things with
+ if (!isset($XML_RPC_xh[$parser]['ac'])) {
+ $XML_RPC_xh[$parser]['ac'] = '';
+ }
+ $XML_RPC_xh[$parser]['ac'] .= $data;
+ }
+}
+
+/**
+ * The common methods and properties for all of the XML_RPC classes
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Base {
+
+ /**
+ * PEAR Error handling
+ *
+ * @return object PEAR_Error object
+ */
+ function raiseError($msg, $code)
+ {
+ include_once 'PEAR.inc';
+ if (is_object(@$this)) {
+ log_error(get_class($this) . ': ' . $msg . " {$code}");
+ return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+ } else {
+ log_error("XML_RPC: " . ': ' . $msg . " {$code}");
+ return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+ }
+ }
+
+ /**
+ * Tell whether something is a PEAR_Error object
+ *
+ * @param mixed $value the item to check
+ *
+ * @return bool whether $value is a PEAR_Error object or not
+ *
+ * @access public
+ */
+ function isError($value)
+ {
+ return is_a($value, 'PEAR_Error');
+ }
+}
+
+/**
+ * The methods and properties for submitting XML RPC requests
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Client extends XML_RPC_Base {
+
+ /**
+ * The path and name of the RPC server script you want the request to go to
+ * @var string
+ */
+ var $path = '';
+
+ /**
+ * The name of the remote server to connect to
+ * @var string
+ */
+ var $server = '';
+
+ /**
+ * The protocol to use in contacting the remote server
+ * @var string
+ */
+ var $protocol = 'http://';
+
+ /**
+ * The port for connecting to the remote server
+ *
+ * The default is 80 for http:// connections
+ * and 443 for https:// and ssl:// connections.
+ *
+ * @var integer
+ */
+ var $port = 80;
+
+ /**
+ * A user name for accessing the RPC server
+ * @var string
+ * @see XML_RPC_Client::setCredentials()
+ */
+ var $username = '';
+
+ /**
+ * A password for accessing the RPC server
+ * @var string
+ * @see XML_RPC_Client::setCredentials()
+ */
+ var $password = '';
+
+ /**
+ * The name of the proxy server to use, if any
+ * @var string
+ */
+ var $proxy = '';
+
+ /**
+ * The protocol to use in contacting the proxy server, if any
+ * @var string
+ */
+ var $proxy_protocol = 'http://';
+
+ /**
+ * The port for connecting to the proxy server
+ *
+ * The default is 8080 for http:// connections
+ * and 443 for https:// and ssl:// connections.
+ *
+ * @var integer
+ */
+ var $proxy_port = 8080;
+
+ /**
+ * A user name for accessing the proxy server
+ * @var string
+ */
+ var $proxy_user = '';
+
+ /**
+ * A password for accessing the proxy server
+ * @var string
+ */
+ var $proxy_pass = '';
+
+ /**
+ * The error number, if any
+ * @var integer
+ */
+ var $errno = 0;
+
+ /**
+ * The error message, if any
+ * @var string
+ */
+ var $errstr = '';
+
+ /**
+ * The current debug mode (1 = on, 0 = off)
+ * @var integer
+ */
+ var $debug = 0;
+
+ /**
+ * The HTTP headers for the current request.
+ * @var string
+ */
+ var $headers = '';
+
+
+ /**
+ * Sets the object's properties
+ *
+ * @param string $path the path and name of the RPC server script
+ * you want the request to go to
+ * @param string $server the URL of the remote server to connect to.
+ * If this parameter doesn't specify a
+ * protocol and $port is 443, ssl:// is
+ * assumed.
+ * @param integer $port a port for connecting to the remote server.
+ * Defaults to 80 for http:// connections and
+ * 443 for https:// and ssl:// connections.
+ * @param string $proxy the URL of the proxy server to use, if any.
+ * If this parameter doesn't specify a
+ * protocol and $port is 443, ssl:// is
+ * assumed.
+ * @param integer $proxy_port a port for connecting to the remote server.
+ * Defaults to 8080 for http:// connections and
+ * 443 for https:// and ssl:// connections.
+ * @param string $proxy_user a user name for accessing the proxy server
+ * @param string $proxy_pass a password for accessing the proxy server
+ *
+ * @return void
+ */
+ function XML_RPC_Client($path, $server, $port = 0,
+ $proxy = '', $proxy_port = 0,
+ $proxy_user = '', $proxy_pass = '')
+ {
+ $this->path = $path;
+ $this->proxy_user = $proxy_user;
+ $this->proxy_pass = $proxy_pass;
+
+ preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+ if ($match[1] == '') {
+ if ($port == 443) {
+ $this->server = $match[2];
+ $this->protocol = 'ssl://';
+ $this->port = 443;
+ } else {
+ $this->server = $match[2];
+ if ($port) {
+ $this->port = $port;
+ }
+ }
+ } elseif ($match[1] == 'http://') {
+ $this->server = $match[2];
+ if ($port) {
+ $this->port = $port;
+ }
+ } else {
+ $this->server = $match[2];
+ $this->protocol = 'ssl://';
+ if ($port) {
+ $this->port = $port;
+ } else {
+ $this->port = 443;
+ }
+ }
+
+ if ($proxy) {
+ preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+ if ($match[1] == '') {
+ if ($proxy_port == 443) {
+ $this->proxy = $match[2];
+ $this->proxy_protocol = 'ssl://';
+ $this->proxy_port = 443;
+ } else {
+ $this->proxy = $match[2];
+ if ($proxy_port) {
+ $this->proxy_port = $proxy_port;
+ }
+ }
+ } elseif ($match[1] == 'http://') {
+ $this->proxy = $match[2];
+ if ($proxy_port) {
+ $this->proxy_port = $proxy_port;
+ }
+ } else {
+ $this->proxy = $match[2];
+ $this->proxy_protocol = 'ssl://';
+ if ($proxy_port) {
+ $this->proxy_port = $proxy_port;
+ } else {
+ $this->proxy_port = 443;
+ }
+ }
+ }
+ }
+
+ /**
+ * Change the current debug mode
+ *
+ * @param int $in where 1 = on, 0 = off
+ *
+ * @return void
+ */
+ function setDebug($in)
+ {
+ if ($in) {
+ $this->debug = 1;
+ } else {
+ $this->debug = 0;
+ }
+ }
+
+ /**
+ * Sets whether strings that contain characters which may cause PHP's
+ * SAX-based XML parser to break should be automatically base64 encoded
+ *
+ * This is is a workaround for systems that don't have PHP's mbstring
+ * extension available.
+ *
+ * @param int $in where 1 = on, 0 = off
+ *
+ * @return void
+ */
+ function setAutoBase64($in)
+ {
+ if ($in) {
+ $GLOBALS['XML_RPC_auto_base64'] = true;
+ } else {
+ $GLOBALS['XML_RPC_auto_base64'] = false;
+ }
+ }
+
+ /**
+ * Set username and password properties for connecting to the RPC server
+ *
+ * @param string $u the user name
+ * @param string $p the password
+ *
+ * @return void
+ *
+ * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+ */
+ function setCredentials($u, $p)
+ {
+ $this->username = $u;
+ $this->password = $p;
+ }
+
+ /**
+ * Transmit the RPC request via HTTP 1.0 protocol
+ *
+ * @param object $msg the XML_RPC_Message object
+ * @param int $timeout how many seconds to wait for the request
+ *
+ * @return object an XML_RPC_Response object. 0 is returned if any
+ * problems happen.
+ *
+ * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+ * XML_RPC_Client::setCredentials()
+ */
+ function send($msg, $timeout = 0)
+ {
+ if (!is_a($msg, 'XML_RPC_Message')) {
+ $this->errstr = sprintf(
+ gettext(
+ "send()'s %s parameter must be an XML_RPC_Message object."
+ ), $msg);
+ $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
+ return 0;
+ }
+ $msg->debug = $this->debug;
+ return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+ $timeout, $this->username,
+ $this->password);
+ }
+
+ /**
+ * Transmit the RPC request via HTTP 1.0 protocol
+ *
+ * Requests should be sent using XML_RPC_Client send() rather than
+ * calling this method directly.
+ *
+ * @param object $msg the XML_RPC_Message object
+ * @param string $server the server to send the request to
+ * @param int $port the server port send the request to
+ * @param int $timeout how many seconds to wait for the request
+ * before giving up
+ * @param string $username a user name for accessing the RPC server
+ * @param string $password a password for accessing the RPC server
+ *
+ * @return object an XML_RPC_Response object. 0 is returned if any
+ * problems happen.
+ *
+ * @access protected
+ * @see XML_RPC_Client::send()
+ */
+ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+ $username = '', $password = '')
+ {
+ // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
+ if ($username != $this->username) {
+ $this->setCredentials($username, $password);
+ }
+
+ // Only create the payload if it was not created previously
+ if (empty($msg->payload)) {
+ $msg->createPayload();
+ }
+ $this->createHeaders($msg);
+
+ $op = $this->headers . "\r\n\r\n";
+ $op .= $msg->payload;
+
+ if ($this->debug) {
+ print "\n<pre>---SENT---\n";
+ print $op;
+ print "\n---END---</pre>\n";
+ }
+
+ /*
+ * If we're using a proxy open a socket to the proxy server
+ * instead to the xml-rpc server
+ */
+ if ($this->proxy) {
+ if ($this->proxy_protocol == 'http://') {
+ $protocol = '';
+ } else {
+ $protocol = $this->proxy_protocol;
+ }
+ if ($timeout > 0) {
+ $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+ $this->errno, $this->errstr, $timeout);
+ } else {
+ $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+ $this->errno, $this->errstr);
+ }
+ } else {
+ if ($this->protocol == 'http://') {
+ $protocol = '';
+ } else {
+ $protocol = $this->protocol;
+ }
+ if ($timeout > 0) {
+ $fp = @fsockopen($protocol . $server, $port,
+ $this->errno, $this->errstr, $timeout);
+ } else {
+ $fp = @fsockopen($protocol . $server, $port,
+ $this->errno, $this->errstr);
+ }
+ }
+
+ /*
+ * Just raising the error without returning it is strange,
+ * but keep it here for backwards compatibility.
+ */
+ if (!$fp && $this->proxy) {
+ $this->raiseError(sprintf(gettext('Connection to proxy server
+ %1$s:%2$s failed. %3$s')
+ ,$this->proxy,$this->proxy_port,$this->errstr),
+ XML_RPC_ERROR_CONNECTION_FAILED);
+ return 0;
+ } elseif (!$fp) {
+ $this->raiseError(sprintf(gettext('Connection to RPC server
+ %1$s:%2$s failed. %3$s')
+ ,$server,$port,$this->errstr),
+ XML_RPC_ERROR_CONNECTION_FAILED);
+ return 0;
+ }
+
+ if ($timeout) {
+ /*
+ * Using socket_set_timeout() because stream_set_timeout()
+ * was introduced in 4.3.0, but we need to support 4.2.0.
+ */
+ socket_set_timeout($fp, $timeout);
+ }
+
+ if (!fputs($fp, $op, strlen($op))) {
+ $this->errstr = 'Write error';
+ return 0;
+ }
+ $resp = $msg->parseResponseFile($fp);
+
+ $meta = socket_get_status($fp);
+ if ($meta['timed_out']) {
+ fclose($fp);
+ $this->errstr = 'RPC server did not send response before timeout.';
+ $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
+ return 0;
+ }
+
+ fclose($fp);
+ return $resp;
+ }
+
+ /**
+ * Determines the HTTP headers and puts it in the $headers property
+ *
+ * @param object $msg the XML_RPC_Message object
+ *
+ * @return boolean TRUE if okay, FALSE if the message payload isn't set.
+ *
+ * @access protected
+ */
+ function createHeaders($msg)
+ {
+ if (empty($msg->payload)) {
+ return false;
+ }
+ if ($this->proxy) {
+ $this->headers = 'POST ' . ($this->protocol=='ssl://'?'https://':$this->protocol). $this->server;
+ if ($this->proxy_port) {
+ $this->headers .= ':' . $this->port;
+ }
+ } else {
+ $this->headers = 'POST ';
+ }
+ $this->headers .= $this->path. " HTTP/1.0\r\n";
+
+ $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
+ $this->headers .= 'Host: ' . $this->server . "\r\n";
+
+ if ($this->proxy && $this->proxy_user) {
+ $this->headers .= 'Proxy-Authorization: Basic '
+ . base64_encode("$this->proxy_user:$this->proxy_pass")
+ . "\r\n";
+ }
+
+ // thanks to Grant Rauscher <grant7@firstworld.net> for this
+ if ($this->username) {
+ $this->headers .= 'Authorization: Basic '
+ . base64_encode("$this->username:$this->password")
+ . "\r\n";
+ }
+
+ $this->headers .= "Content-Type: text/xml\r\n";
+ $this->headers .= 'Content-Length: ' . strlen($msg->payload);
+ return true;
+ }
+}
+
+/**
+ * The methods and properties for interpreting responses to XML RPC requests
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Response extends XML_RPC_Base
+{
+ var $xv;
+ var $fn;
+ var $fs;
+ var $hdrs;
+
+ /**
+ * @return void
+ */
+ function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+ {
+ if ($fcode != 0) {
+ $this->fn = $fcode;
+ $this->fs = htmlspecialchars($fstr);
+ } else {
+ $this->xv = $val;
+ }
+ }
+
+ /**
+ * @return int the error code
+ */
+ function faultCode()
+ {
+ if (isset($this->fn)) {
+ return $this->fn;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * @return string the error string
+ */
+ function faultString()
+ {
+ return $this->fs;
+ }
+
+ /**
+ * @return mixed the value
+ */
+ function value()
+ {
+ return $this->xv;
+ }
+
+ /**
+ * @return string the error message in XML format
+ */
+ function serialize()
+ {
+ $rs = "<methodResponse>\n";
+ if ($this->fn) {
+ $rs .= "<fault>
+ <value>
+ <struct>
+ <member>
+ <name>faultCode</name>
+ <value><int>" . $this->fn . "</int></value>
+ </member>
+ <member>
+ <name>faultString</name>
+ <value><string>" . $this->fs . "</string></value>
+ </member>
+ </struct>
+ </value>
+</fault>";
+ } else {
+ $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
+ "</param>\n</params>";
+ }
+ $rs .= "\n</methodResponse>";
+ return $rs;
+ }
+}
+
+/**
+ * The methods and properties for composing XML RPC messages
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Message extends XML_RPC_Base
+{
+ /**
+ * Should the payload's content be passed through mb_convert_encoding()?
+ *
+ * @see XML_RPC_Message::setConvertPayloadEncoding()
+ * @since Property available since Release 1.5.1
+ * @var boolean
+ */
+ var $convert_payload_encoding = false;
+
+ /**
+ * The current debug mode (1 = on, 0 = off)
+ * @var integer
+ */
+ var $debug = 0;
+
+ /**
+ * The encoding to be used for outgoing messages
+ *
+ * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
+ *
+ * @var string
+ * @see XML_RPC_Message::setSendEncoding(),
+ * $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+ */
+ var $send_encoding = '';
+
+ /**
+ * The method presently being evaluated
+ * @var string
+ */
+ var $methodname = '';
+
+ /**
+ * @var array
+ */
+ var $params = array();
+
+ /**
+ * The XML message being generated
+ * @var string
+ */
+ var $payload = '';
+
+ /**
+ * Should extra line breaks be removed from the payload?
+ * @since Property available since Release 1.4.6
+ * @var boolean
+ */
+ var $remove_extra_lines = true;
+
+ /**
+ * The XML response from the remote server
+ * @since Property available since Release 1.4.6
+ * @var string
+ */
+ var $response_payload = '';
+
+
+ /**
+ * @return void
+ */
+ function XML_RPC_Message($meth, $pars = 0)
+ {
+ $this->methodname = $meth;
+ if (is_array($pars) && sizeof($pars) > 0) {
+ for ($i = 0; $i < sizeof($pars); $i++) {
+ $this->addParam($pars[$i]);
+ }
+ }
+ }
+
+ /**
+ * Produces the XML declaration including the encoding attribute
+ *
+ * The encoding is determined by this class' <var>$send_encoding</var>
+ * property. If the <var>$send_encoding</var> property is not set, use
+ * <var>$GLOBALS['XML_RPC_defencoding']</var>.
+ *
+ * @return string the XML declaration and <methodCall> element
+ *
+ * @see XML_RPC_Message::setSendEncoding(),
+ * XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+ */
+ function xml_header()
+ {
+ global $XML_RPC_defencoding;
+
+ if (!$this->send_encoding) {
+ $this->send_encoding = $XML_RPC_defencoding;
+ }
+ return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
+ . "\n<methodCall>\n";
+ }
+
+ /**
+ * @return string the closing </methodCall> tag
+ */
+ function xml_footer()
+ {
+ return "</methodCall>\n";
+ }
+
+ /**
+ * Fills the XML_RPC_Message::$payload property
+ *
+ * Part of the process makes sure all line endings are in DOS format
+ * (CRLF), which is probably required by specifications.
+ *
+ * If XML_RPC_Message::setConvertPayloadEncoding() was set to true,
+ * the payload gets passed through mb_convert_encoding()
+ * to ensure the payload matches the encoding set in the
+ * XML declaration. The encoding type can be manually set via
+ * XML_RPC_Message::setSendEncoding().
+ *
+ * @return void
+ *
+ * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+ * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'],
+ * XML_RPC_Message::setConvertPayloadEncoding()
+ */
+ function createPayload()
+ {
+ $this->payload = $this->xml_header();
+ $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
+ $this->payload .= "<params>\n";
+ for ($i = 0; $i < sizeof($this->params); $i++) {
+ $p = $this->params[$i];
+ $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
+ }
+ $this->payload .= "</params>\n";
+ $this->payload .= $this->xml_footer();
+ if ($this->remove_extra_lines) {
+ $this->payload = preg_replace("@[\r\n]+@", "\r\n", $this->payload);
+ } else {
+ $this->payload = preg_replace("@\r\n|\n|\r|\n\r@", "\r\n", $this->payload);
+ }
+ if ($this->convert_payload_encoding) {
+ $this->payload = mb_convert_encoding($this->payload, $this->send_encoding);
+ }
+ }
+
+ /**
+ * @return string the name of the method
+ */
+ function method($meth = '')
+ {
+ if ($meth != '') {
+ $this->methodname = $meth;
+ }
+ return $this->methodname;
+ }
+
+ /**
+ * @return string the payload
+ */
+ function serialize()
+ {
+ $this->createPayload();
+ return $this->payload;
+ }
+
+ /**
+ * @return void
+ */
+ function addParam($par)
+ {
+ $this->params[] = $par;
+ }
+
+ /**
+ * Obtains an XML_RPC_Value object for the given parameter
+ *
+ * @param int $i the index number of the parameter to obtain
+ *
+ * @return object the XML_RPC_Value object.
+ * If the parameter doesn't exist, an XML_RPC_Response object.
+ *
+ * @since Returns XML_RPC_Response object on error since Release 1.3.0
+ */
+ function getParam($i)
+ {
+ global $XML_RPC_err, $XML_RPC_str;
+
+ if (isset($this->params[$i])) {
+ return $this->params[$i];
+ } else {
+ $this->raiseError(gettext('The submitted request did not contain this parameter'),
+ XML_RPC_ERROR_INCORRECT_PARAMS);
+ return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
+ $XML_RPC_str['incorrect_params']);
+ }
+ }
+
+ /**
+ * @return int the number of parameters
+ */
+ function getNumParams()
+ {
+ return sizeof($this->params);
+ }
+
+ /**
+ * Sets whether the payload's content gets passed through
+ * mb_convert_encoding()
+ *
+ * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
+ *
+ * @param int $in where 1 = on, 0 = off
+ *
+ * @return void
+ *
+ * @see XML_RPC_Message::setSendEncoding()
+ * @since Method available since Release 1.5.1
+ */
+ function setConvertPayloadEncoding($in)
+ {
+ if ($in && !function_exists('mb_convert_encoding')) {
+ return $this->raiseError(gettext('mb_convert_encoding() is not available'),
+ XML_RPC_ERROR_PROGRAMMING);
+ }
+ $this->convert_payload_encoding = $in;
+ }
+
+ /**
+ * Sets the XML declaration's encoding attribute
+ *
+ * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+ *
+ * @return void
+ *
+ * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header()
+ * @since Method available since Release 1.2.0
+ */
+ function setSendEncoding($type)
+ {
+ $this->send_encoding = $type;
+ }
+
+ /**
+ * Determine the XML's encoding via the encoding attribute
+ * in the XML declaration
+ *
+ * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+ * or US-ASCII, $XML_RPC_defencoding will be returned.
+ *
+ * @param string $data the XML that will be parsed
+ *
+ * @return string the encoding to be used
+ *
+ * @link http://php.net/xml_parser_create
+ * @since Method available since Release 1.2.0
+ */
+ function getEncoding($data)
+ {
+ global $XML_RPC_defencoding;
+
+ if (preg_match('@<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]@',
+ $data, $match))
+ {
+ $match[1] = trim(strtoupper($match[1]));
+ switch ($match[1]) {
+ case 'ISO-8859-1':
+ case 'UTF-8':
+ case 'US-ASCII':
+ return $match[1];
+ break;
+
+ default:
+ return $XML_RPC_defencoding;
+ }
+ } else {
+ return $XML_RPC_defencoding;
+ }
+ }
+
+ /**
+ * @return object a new XML_RPC_Response object
+ */
+ function parseResponseFile($fp)
+ {
+ $ipd = '';
+ while ($data = @fread($fp, 8192)) {
+ $ipd .= $data;
+ }
+ return $this->parseResponse($ipd);
+ }
+
+ /**
+ * @return object a new XML_RPC_Response object
+ */
+ function parseResponse($data = '')
+ {
+ global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+
+ $encoding = $this->getEncoding($data);
+ $parser_resource = xml_parser_create($encoding);
+ $parser = (int) $parser_resource;
+
+ $XML_RPC_xh = array();
+ $XML_RPC_xh[$parser] = array();
+
+ $XML_RPC_xh[$parser]['cm'] = 0;
+ $XML_RPC_xh[$parser]['isf'] = 0;
+ $XML_RPC_xh[$parser]['ac'] = '';
+ $XML_RPC_xh[$parser]['qt'] = '';
+ $XML_RPC_xh[$parser]['stack'] = array();
+ $XML_RPC_xh[$parser]['valuestack'] = array();
+
+ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
+ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
+ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
+
+ $hdrfnd = 0;
+ if ($this->debug) {
+ print "\n<pre>---GOT---\n";
+ print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+ print "\n---END---</pre>\n";
+ }
+
+ // See if response is a 200 or a 100 then a 200, else raise error.
+ // But only do this if we're using the HTTP protocol.
+ if (preg_match('@^HTTP@', $data) &&
+ !preg_match('@^HTTP/[0-9\.]+ 200 @', $data) &&
+ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data))
+ {
+ $errstr = substr($data, 0, strpos($data, "\n") - 1);
+ error_log(sprintf(gettext("HTTP error, got response: %s"),$errstr));
+ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
+ $XML_RPC_str['http_error'] . ' (' .
+ $errstr . ')');
+ xml_parser_free($parser_resource);
+ return $r;
+ }
+
+ // gotta get rid of headers here
+ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
+ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
+ $data = substr($data, $brpos + 4);
+ $hdrfnd = 1;
+ }
+
+ /*
+ * be tolerant of junk after methodResponse
+ * (e.g. javascript automatically inserted by free hosts)
+ * thanks to Luca Mariano <luca.mariano@email.it>
+ */
+ $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
+ $this->response_payload = $data;
+
+ if (!xml_parse($parser_resource, $data, sizeof($data))) {
+ // thanks to Peter Kocks <peter.kocks@baygate.com>
+ if (xml_get_current_line_number($parser_resource) == 1) {
+ /* We already error on this in the GUI, no need to log it and cause a PHP error. */
+ //$errstr = gettext("XML error at line 1, check URL");
+ } else {
+ $errstr = sprintf('XML error: %s at line %d',
+ xml_error_string(xml_get_error_code($parser_resource)),
+ xml_get_current_line_number($parser_resource));
+ }
+ if (!empty($errstr))
+ error_log($errstr);
+ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
+ $XML_RPC_str['invalid_return']);
+ xml_parser_free($parser_resource);
+ return $r;
+ }
+
+ xml_parser_free($parser_resource);
+
+ if ($this->debug) {
+ print "\n<pre>---PARSED---\n";
+ var_dump($XML_RPC_xh[$parser]['value']);
+ print "---END---</pre>\n";
+ }
+
+ if ($XML_RPC_xh[$parser]['isf'] > 1) {
+ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
+ $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
+ } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
+ // then something odd has happened
+ // and it's time to generate a client side error
+ // indicating something odd went on
+ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
+ $XML_RPC_str['invalid_return']);
+ } else {
+ $v = $XML_RPC_xh[$parser]['value'];
+ if ($XML_RPC_xh[$parser]['isf']) {
+ $f = $v->structmem('faultCode');
+ $fs = $v->structmem('faultString');
+ $r = new XML_RPC_Response($v, $f->scalarval(),
+ $fs->scalarval());
+ } else {
+ $r = new XML_RPC_Response($v);
+ }
+ }
+ $r->hdrs = preg_split("@\r?\n@", $XML_RPC_xh[$parser]['ha'][1]);
+ return $r;
+ }
+}
+
+/**
+ * The methods and properties that represent data in XML RPC format
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Value extends XML_RPC_Base
+{
+ var $me = array();
+ var $mytype = 0;
+
+ /**
+ * @return void
+ */
+ function XML_RPC_Value($val = -1, $type = '')
+ {
+ $this->me = array();
+ $this->mytype = 0;
+ if ($val != -1 || $type != '') {
+ if ($type == '') {
+ $type = 'string';
+ }
+ if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) {
+ // XXX
+ // need some way to report this error
+ } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) {
+ $this->addScalar($val, $type);
+ } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) {
+ $this->addArray($val);
+ } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) {
+ $this->addStruct($val);
+ }
+ }
+ }
+
+ /**
+ * @return int returns 1 if successful or 0 if there are problems
+ */
+ function addScalar($val, $type = 'string')
+ {
+ if ($this->mytype == 1) {
+ $this->raiseError(gettext('Scalar can have only one value'),
+ XML_RPC_ERROR_INVALID_TYPE);
+ return 0;
+ }
+ $typeof = $GLOBALS['XML_RPC_Types'][$type];
+ if ($typeof != 1) {
+ $this->raiseError(
+ sprintf(gettext("Not a scalar type (%s)"), $typeof),
+ XML_RPC_ERROR_INVALID_TYPE);
+ return 0;
+ }
+
+ if ($type == $GLOBALS['XML_RPC_Boolean']) {
+ if (strcasecmp($val, 'true') == 0
+ || $val == 1
+ || ($val == true && strcasecmp($val, 'false')))
+ {
+ $val = 1;
+ } else {
+ $val = 0;
+ }
+ }
+
+ if ($this->mytype == 2) {
+ // we're adding to an array here
+ $ar = $this->me['array'];
+ $ar[] = new XML_RPC_Value($val, $type);
+ $this->me['array'] = $ar;
+ } else {
+ // a scalar, so set the value and remember we're scalar
+ $this->me[$type] = $val;
+ $this->mytype = $typeof;
+ }
+ return 1;
+ }
+
+ /**
+ * @return int returns 1 if successful or 0 if there are problems
+ */
+ function addArray($vals)
+ {
+ if ($this->mytype != 0) {
+ $this->raiseError(
+ sprintf(gettext('Already initialized as a [%s]'), $this->kindOf()),
+ XML_RPC_ERROR_ALREADY_INITIALIZED);
+ return 0;
+ }
+ $this->mytype = $GLOBALS['XML_RPC_Types']['array'];
+ $this->me['array'] = $vals;
+ return 1;
+ }
+
+ /**
+ * @return int returns 1 if successful or 0 if there are problems
+ */
+ function addStruct($vals)
+ {
+ if ($this->mytype != 0) {
+ $this->raiseError(
+ sprintf(gettext('Already initialized as a [%s]'), $this->kindOf()),
+ XML_RPC_ERROR_ALREADY_INITIALIZED);
+ return 0;
+ }
+ $this->mytype = $GLOBALS['XML_RPC_Types']['struct'];
+ $this->me['struct'] = $vals;
+ return 1;
+ }
+
+ /**
+ * @return void
+ */
+ function dump($ar)
+ {
+ reset($ar);
+ foreach ($ar as $key => $val) {
+ echo "$key => $val<br />";
+ if ($key == 'array') {
+ foreach ($val as $key2 => $val2) {
+ echo "-- $key2 => $val2<br />";
+ }
+ }
+ }
+ }
+
+ /**
+ * @return string the data type of the current value
+ */
+ function kindOf()
+ {
+ switch ($this->mytype) {
+ case 3:
+ return 'struct';
+
+ case 2:
+ return 'array';
+
+ case 1:
+ return 'scalar';
+
+ default:
+ return 'undef';
+ }
+ }
+
+ /**
+ * @return string the data in XML format
+ */
+ function serializedata($typ, $val)
+ {
+ $rs = '';
+ if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) {
+ // XXX
+ // need some way to report this error
+ return;
+ }
+ switch ($GLOBALS['XML_RPC_Types'][$typ]) {
+ case 3:
+ // struct
+ $rs .= "<struct>\n";
+ reset($val);
+ foreach ($val as $key2 => $val2) {
+ $rs .= "<member><name>" . htmlspecialchars($key2) . "</name>\n";
+ $rs .= $this->serializeval($val2);
+ $rs .= "</member>\n";
+ }
+ $rs .= '</struct>';
+ break;
+
+ case 2:
+ // array
+ $rs .= "<array>\n<data>\n";
+ foreach ($val as $value) {
+ $rs .= $this->serializeval($value);
+ }
+ $rs .= "</data>\n</array>";
+ break;
+
+ case 1:
+ switch ($typ) {
+ case $GLOBALS['XML_RPC_Base64']:
+ $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
+ break;
+ case $GLOBALS['XML_RPC_Boolean']:
+ $rs .= "<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
+ break;
+ case $GLOBALS['XML_RPC_String']:
+ $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
+ break;
+ default:
+ $rs .= "<${typ}>${val}</${typ}>";
+ }
+ }
+ return $rs;
+ }
+
+ /**
+ * @return string the data in XML format
+ */
+ function serialize()
+ {
+ return $this->serializeval($this);
+ }
+
+ /**
+ * @return string the data in XML format
+ */
+ function serializeval($o)
+ {
+ if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
+ return '';
+ }
+ $ar = $o->me;
+ reset($ar);
+ list($typ, $val) = each($ar);
+ return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
+ }
+
+ /**
+ * @return mixed the contents of the element requested
+ */
+ function structmem($m)
+ {
+ return $this->me['struct'][$m];
+ }
+
+ /**
+ * @return void
+ */
+ function structreset()
+ {
+ reset($this->me['struct']);
+ }
+
+ /**
+ * @return the key/value pair of the struct's current element
+ */
+ function structeach()
+ {
+ return each($this->me['struct']);
+ }
+
+ /**
+ * @return mixed the current value
+ */
+ function getval()
+ {
+ // UNSTABLE
+
+ reset($this->me);
+ $b = current($this->me);
+
+ // contributed by I Sofer, 2001-03-24
+ // add support for nested arrays to scalarval
+ // i've created a new method here, so as to
+ // preserve back compatibility
+
+ if (is_array($b)) {
+ foreach ($b as $id => $cont) {
+ $b[$id] = $cont->scalarval();
+ }
+ }
+
+ // add support for structures directly encoding php objects
+ if (is_object($b)) {
+ $t = get_object_vars($b);
+ foreach ($t as $id => $cont) {
+ $t[$id] = $cont->scalarval();
+ }
+ foreach ($t as $id => $cont) {
+ $b->$id = $cont;
+ }
+ }
+
+ // end contrib
+ return $b;
+ }
+
+ /**
+ * @return mixed the current element's scalar value. If the value is
+ * not scalar, FALSE is returned.
+ */
+ function scalarval()
+ {
+ reset($this->me);
+ $v = current($this->me);
+ if (!is_scalar($v)) {
+ $v = false;
+ }
+ return $v;
+ }
+
+ /**
+ * @return string
+ */
+ function scalartyp()
+ {
+ reset($this->me);
+ $a = key($this->me);
+ if ($a == $GLOBALS['XML_RPC_I4']) {
+ $a = $GLOBALS['XML_RPC_Int'];
+ }
+ return $a;
+ }
+
+ /**
+ * @return mixed the struct's current element
+ */
+ function arraymem($m)
+ {
+ return $this->me['array'][$m];
+ }
+
+ /**
+ * @return int the number of elements in the array
+ */
+ function arraysize()
+ {
+ reset($this->me);
+ list($a, $b) = each($this->me);
+ return sizeof($b);
+ }
+
+ /**
+ * Determines if the item submitted is an XML_RPC_Value object
+ *
+ * @param mixed $val the variable to be evaluated
+ *
+ * @return bool TRUE if the item is an XML_RPC_Value object
+ *
+ * @static
+ * @since Method available since Release 1.3.0
+ */
+ function isValue($val)
+ {
+ return (strtolower(get_class($val)) == 'xml_rpc_value');
+ }
+}
+
+/**
+ * Return an ISO8601 encoded string
+ *
+ * While timezones ought to be supported, the XML-RPC spec says:
+ *
+ * "Don't assume a timezone. It should be specified by the server in its
+ * documentation what assumptions it makes about timezones."
+ *
+ * This routine always assumes localtime unless $utc is set to 1, in which
+ * case UTC is assumed and an adjustment for locale is made when encoding.
+ *
+ * @return string the formatted date
+ */
+function XML_RPC_iso8601_encode($timet, $utc = 0)
+{
+ if (!$utc) {
+ $t = strftime('%Y%m%dT%H:%M:%S', $timet);
+ } else {
+ if (function_exists('gmstrftime')) {
+ // gmstrftime doesn't exist in some versions
+ // of PHP
+ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet);
+ } else {
+ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z'));
+ }
+ }
+ return $t;
+}
+
+/**
+ * Convert a datetime string into a Unix timestamp
+ *
+ * While timezones ought to be supported, the XML-RPC spec says:
+ *
+ * "Don't assume a timezone. It should be specified by the server in its
+ * documentation what assumptions it makes about timezones."
+ *
+ * This routine always assumes localtime unless $utc is set to 1, in which
+ * case UTC is assumed and an adjustment for locale is made when encoding.
+ *
+ * @return int the unix timestamp of the date submitted
+ */
+function XML_RPC_iso8601_decode($idate, $utc = 0)
+{
+ $t = 0;
+ if (preg_match('@([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})@', $idate, $regs)) {
+ if ($utc) {
+ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+ } else {
+ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+ }
+ }
+ return $t;
+}
+
+/**
+ * Converts an XML_RPC_Value object into native PHP types
+ *
+ * @param object $XML_RPC_val the XML_RPC_Value object to decode
+ *
+ * @return mixed the PHP values
+ */
+function XML_RPC_decode($XML_RPC_val)
+{
+ $kind = $XML_RPC_val->kindOf();
+
+ if ($kind == 'scalar') {
+ return $XML_RPC_val->scalarval();
+
+ } elseif ($kind == 'array') {
+ $size = $XML_RPC_val->arraysize();
+ $arr = array();
+ for ($i = 0; $i < $size; $i++) {
+ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
+ }
+ return $arr;
+
+ } elseif ($kind == 'struct') {
+ $XML_RPC_val->structreset();
+ $arr = array();
+ while (list($key, $value) = $XML_RPC_val->structeach()) {
+ $arr[$key] = XML_RPC_decode($value);
+ }
+ return $arr;
+ }
+}
+
+/**
+ * Converts native PHP types into an XML_RPC_Value object
+ *
+ * @param mixed $php_val the PHP value or variable you want encoded
+ *
+ * @return object the XML_RPC_Value object
+ */
+function XML_RPC_encode($php_val)
+{
+ $type = gettype($php_val);
+ $XML_RPC_val = new XML_RPC_Value;
+
+ switch ($type) {
+ case 'array':
+ if (empty($php_val)) {
+ $XML_RPC_val->addArray($php_val);
+ break;
+ }
+ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
+ if (empty($tmp)) {
+ $arr = array();
+ foreach ($php_val as $k => $v) {
+ $arr[$k] = XML_RPC_encode($v);
+ }
+ $XML_RPC_val->addArray($arr);
+ break;
+ }
+ // fall though if it's not an enumerated array
+
+ case 'object':
+ $arr = array();
+ foreach ($php_val as $k => $v) {
+ $arr[$k] = XML_RPC_encode($v);
+ }
+ $XML_RPC_val->addStruct($arr);
+ break;
+
+ case 'integer':
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
+ break;
+
+ case 'double':
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
+ break;
+
+ case 'string':
+ case 'NULL':
+ if (preg_match('@^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$@', $php_val)) {
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']);
+ } elseif ($GLOBALS['XML_RPC_auto_base64']
+ && preg_match("@[^ -~\t\r\n]@", $php_val))
+ {
+ // Characters other than alpha-numeric, punctuation, SP, TAB,
+ // LF and CR break the XML parser, encode value via Base 64.
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']);
+ } else {
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']);
+ }
+ break;
+
+ case 'boolean':
+ // Add support for encoding/decoding of booleans, since they
+ // are supported in PHP
+ // by <G_Giunta_2001-02-29>
+ $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']);
+ break;
+
+ case 'unknown type':
+ default:
+ $XML_RPC_val = false;
+ }
+ return $XML_RPC_val;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?>
diff --git a/src/etc/inc/xmlrpc_server.inc b/src/etc/inc/xmlrpc_server.inc
new file mode 100644
index 0000000..f4d8a46
--- /dev/null
+++ b/src/etc/inc/xmlrpc_server.inc
@@ -0,0 +1,678 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Server commands for our PHP implementation of the XML-RPC protocol
+ *
+ * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
+ * It has support for HTTP transport, proxies and authentication.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version SVN: $Id: Server.php 300961 2010-07-03 02:17:34Z danielc $
+ * @link http://pear.php.net/package/XML_RPC
+ */
+
+
+/**
+ * Pull in the XML_RPC class
+ */
+require_once 'xmlrpc_client.inc';
+
+
+/**
+ * signature for system.listMethods: return = array,
+ * parameters = a string or nothing
+ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig']
+ */
+$GLOBALS['XML_RPC_Server_listMethods_sig'] = array(
+ array($GLOBALS['XML_RPC_Array'],
+ $GLOBALS['XML_RPC_String']
+ ),
+ array($GLOBALS['XML_RPC_Array'])
+);
+
+/**
+ * docstring for system.listMethods
+ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc']
+ */
+$GLOBALS['XML_RPC_Server_listMethods_doc'] = gettext('This method lists all the'
+ . ' methods that the XML-RPC server knows how to dispatch');
+
+/**
+ * signature for system.methodSignature: return = array,
+ * parameters = string
+ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig']
+ */
+$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array(
+ array($GLOBALS['XML_RPC_Array'],
+ $GLOBALS['XML_RPC_String']
+ )
+);
+
+/**
+ * docstring for system.methodSignature
+ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc']
+ */
+$GLOBALS['XML_RPC_Server_methodSignature_doc'] = gettext('Returns an array of known'
+ . ' signatures (an array of arrays) for the method name passed. If'
+ . ' no signatures are known, returns a none-array (test for type !='
+ . ' array to detect missing signature)');
+
+/**
+ * signature for system.methodHelp: return = string,
+ * parameters = string
+ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig']
+ */
+$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array(
+ array($GLOBALS['XML_RPC_String'],
+ $GLOBALS['XML_RPC_String']
+ )
+);
+
+/**
+ * docstring for methodHelp
+ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc']
+ */
+$GLOBALS['XML_RPC_Server_methodHelp_doc'] = gettext('Returns help text if defined'
+ . ' for the method passed, otherwise returns an empty string');
+
+/**
+ * dispatch map for the automatically declared XML-RPC methods.
+ * @global array $GLOBALS['XML_RPC_Server_dmap']
+ */
+$GLOBALS['XML_RPC_Server_dmap'] = array(
+ 'system.listMethods' => array(
+ 'function' => 'XML_RPC_Server_listMethods',
+ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'],
+ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc']
+ ),
+ 'system.methodHelp' => array(
+ 'function' => 'XML_RPC_Server_methodHelp',
+ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'],
+ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc']
+ ),
+ 'system.methodSignature' => array(
+ 'function' => 'XML_RPC_Server_methodSignature',
+ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'],
+ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc']
+ )
+);
+
+/**
+ * @global string $GLOBALS['XML_RPC_Server_debuginfo']
+ */
+$GLOBALS['XML_RPC_Server_debuginfo'] = '';
+
+
+/**
+ * Lists all the methods that the XML-RPC server knows how to dispatch
+ *
+ * @return object a new XML_RPC_Response object
+ */
+function XML_RPC_Server_listMethods($server, $m)
+{
+ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
+
+ $v = new XML_RPC_Value();
+ $outAr = array();
+ foreach ($server->dmap as $key => $val) {
+ $outAr[] = new XML_RPC_Value($key, 'string');
+ }
+ foreach ($XML_RPC_Server_dmap as $key => $val) {
+ $outAr[] = new XML_RPC_Value($key, 'string');
+ }
+ $v->addArray($outAr);
+ return new XML_RPC_Response($v);
+}
+
+/**
+ * Returns an array of known signatures (an array of arrays)
+ * for the given method
+ *
+ * If no signatures are known, returns a none-array
+ * (test for type != array to detect missing signature)
+ *
+ * @return object a new XML_RPC_Response object
+ */
+function XML_RPC_Server_methodSignature($server, $m)
+{
+ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
+
+ $methName = $m->getParam(0);
+ $methName = $methName->scalarval();
+ if (strpos($methName, 'system.') === 0) {
+ $dmap = $XML_RPC_Server_dmap;
+ $sysCall = 1;
+ } else {
+ $dmap = $server->dmap;
+ $sysCall = 0;
+ }
+ // print "<!-- ${methName} -->\n";
+ if (isset($dmap[$methName])) {
+ if ($dmap[$methName]['signature']) {
+ $sigs = array();
+ $thesigs = $dmap[$methName]['signature'];
+ for ($i = 0; $i < sizeof($thesigs); $i++) {
+ $cursig = array();
+ $inSig = $thesigs[$i];
+ for ($j = 0; $j < sizeof($inSig); $j++) {
+ $cursig[] = new XML_RPC_Value($inSig[$j], 'string');
+ }
+ $sigs[] = new XML_RPC_Value($cursig, 'array');
+ }
+ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array'));
+ } else {
+ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string'));
+ }
+ } else {
+ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
+ $XML_RPC_str['introspect_unknown']);
+ }
+ return $r;
+}
+
+/**
+ * Returns help text if defined for the method passed, otherwise returns
+ * an empty string
+ *
+ * @return object a new XML_RPC_Response object
+ */
+function XML_RPC_Server_methodHelp($server, $m)
+{
+ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
+
+ $methName = $m->getParam(0);
+ $methName = $methName->scalarval();
+ if (strpos($methName, 'system.') === 0) {
+ $dmap = $XML_RPC_Server_dmap;
+ $sysCall = 1;
+ } else {
+ $dmap = $server->dmap;
+ $sysCall = 0;
+ }
+
+ if (isset($dmap[$methName])) {
+ if ($dmap[$methName]['docstring']) {
+ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']),
+ 'string');
+ } else {
+ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string'));
+ }
+ } else {
+ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
+ $XML_RPC_str['introspect_unknown']);
+ }
+ return $r;
+}
+
+/**
+ * @return void
+ */
+function XML_RPC_Server_debugmsg($m)
+{
+ global $XML_RPC_Server_debuginfo;
+ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n";
+}
+
+
+/**
+ * A server for receiving and replying to XML RPC requests
+ *
+ * <code>
+ * $server = new XML_RPC_Server(
+ * array(
+ * 'isan8' =>
+ * array(
+ * 'function' => 'is_8',
+ * 'signature' =>
+ * array(
+ * array('boolean', 'int'),
+ * array('boolean', 'int', 'boolean'),
+ * array('boolean', 'string'),
+ * array('boolean', 'string', 'boolean'),
+ * ),
+ * 'docstring' => 'Is the value an 8?'
+ * ),
+ * ),
+ * 1,
+ * 0
+ * );
+ * </code>
+ *
+ * @category Web Services
+ * @package XML_RPC
+ * @author Edd Dumbill <edd@usefulinc.com>
+ * @author Stig Bakken <stig@php.net>
+ * @author Martin Jansen <mj@php.net>
+ * @author Daniel Convissor <danielc@php.net>
+ * @copyright 1999-2001 Edd Dumbill, 2001-2010 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_RPC
+ */
+class XML_RPC_Server
+{
+ /**
+ * Should the payload's content be passed through mb_convert_encoding()?
+ *
+ * @see XML_RPC_Server::setConvertPayloadEncoding()
+ * @since Property available since Release 1.5.1
+ * @var boolean
+ */
+ var $convert_payload_encoding = false;
+
+ /**
+ * The dispatch map, listing the methods this server provides.
+ * @var array
+ */
+ var $dmap = array();
+
+ /**
+ * The present response's encoding
+ * @var string
+ * @see XML_RPC_Message::getEncoding()
+ */
+ var $encoding = '';
+
+ /**
+ * Debug mode (0 = off, 1 = on)
+ * @var integer
+ */
+ var $debug = 0;
+
+ /**
+ * The response's HTTP headers
+ * @var string
+ */
+ var $server_headers = '';
+
+ /**
+ * The response's XML payload
+ * @var string
+ */
+ var $server_payload = '';
+
+
+ /**
+ * The HTTP request data
+ * @null
+ */
+ var $client_data = '';
+
+ /**
+ * Constructor for the XML_RPC_Server class
+ *
+ * @param array $dispMap the dispatch map. An associative array
+ * explaining each function. The keys of the main
+ * array are the procedure names used by the
+ * clients. The value is another associative array
+ * that contains up to three elements:
+ * + The 'function' element's value is the name
+ * of the function or method that gets called.
+ * To define a class' method: 'class::method'.
+ * + The 'signature' element (optional) is an
+ * array describing the return values and
+ * parameters
+ * + The 'docstring' element (optional) is a
+ * string describing what the method does
+ * @param int $serviceNow should the HTTP response be sent now?
+ * (1 = yes, 0 = no)
+ * @param int $debug should debug output be displayed?
+ * (1 = yes, 0 = no)
+ *
+ * @return void
+ */
+ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0)
+ {
+
+ if ($debug) {
+ $this->debug = 1;
+ } else {
+ $this->debug = 0;
+ }
+
+ $this->dmap = $dispMap;
+
+ if ($serviceNow) {
+ $this->service();
+ } else {
+ $this->createServerPayload();
+ $this->createServerHeaders();
+ }
+ }
+
+ /**
+ * @return string the debug information if debug debug mode is on
+ */
+ function serializeDebug()
+ {
+ global $XML_RPC_Server_debuginfo;
+
+ if ($this->debug) {
+ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n"
+ . $this->server_payload . $this->client_data
+ . "\n" . '^^^ END POST DATA ^^^');
+ }
+
+ if ($XML_RPC_Server_debuginfo != '') {
+ return "<!-- PEAR XML_RPC SERVER DEBUG INFO:\n\n"
+ . str_replace('--', '- - ', $XML_RPC_Server_debuginfo)
+ . "-->\n";
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Sets whether the payload's content gets passed through
+ * mb_convert_encoding()
+ *
+ * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
+ *
+ * @param int $in where 1 = on, 0 = off
+ *
+ * @return void
+ *
+ * @see XML_RPC_Message::getEncoding()
+ * @since Method available since Release 1.5.1
+ */
+ function setConvertPayloadEncoding($in)
+ {
+ if ($in && !function_exists('mb_convert_encoding')) {
+ return $this->raiseError('mb_convert_encoding() is not available',
+ XML_RPC_ERROR_PROGRAMMING);
+ }
+ $this->convert_payload_encoding = $in;
+ }
+
+ /**
+ * Sends the response
+ *
+ * The encoding and content-type are determined by
+ * XML_RPC_Message::getEncoding()
+ *
+ * @return void
+ *
+ * @uses XML_RPC_Server::createServerPayload(),
+ * XML_RPC_Server::createServerHeaders()
+ */
+ function service()
+ {
+ if (!$this->server_payload) {
+ $this->createServerPayload();
+ }
+ if (!$this->server_headers) {
+ $this->createServerHeaders();
+ }
+
+ /*
+ * $server_headers needs to remain a string for compatibility with
+ * old scripts using this package, but PHP 4.4.2 no longer allows
+ * line breaks in header() calls. So, we split each header into
+ * an individual call. The initial replace handles the off chance
+ * that someone composed a single header with multiple lines, which
+ * the RFCs allow.
+ */
+ $this->server_headers = preg_replace("@[\r\n]+[ \t]+@",
+ ' ', trim($this->server_headers));
+ $headers = preg_split("@[\r\n]+@", $this->server_headers);
+ foreach ($headers as $header)
+ {
+ header($header);
+ }
+
+ print $this->server_payload;
+ }
+
+ /**
+ * Generates the payload and puts it in the $server_payload property
+ *
+ * If XML_RPC_Server::setConvertPayloadEncoding() was set to true,
+ * the payload gets passed through mb_convert_encoding()
+ * to ensure the payload matches the encoding set in the
+ * XML declaration. The encoding type can be manually set via
+ * XML_RPC_Message::setSendEncoding().
+ *
+ * @return void
+ *
+ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding,
+ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug()
+ * @see XML_RPC_Server::setConvertPayloadEncoding()
+ */
+ function createServerPayload()
+ {
+ $this->client_data = file_get_contents("php://input");
+
+ $r = $this->parseRequest($this->client_data);
+ $this->server_payload = '<?xml version="1.0" encoding="'
+ . $this->encoding . '"?>' . "\n"
+ . $this->serializeDebug()
+ . $r->serialize();
+ if ($this->convert_payload_encoding) {
+ $this->server_payload = mb_convert_encoding($this->server_payload,
+ $this->encoding);
+ }
+ }
+
+ /**
+ * Determines the HTTP headers and puts them in the $server_headers
+ * property
+ *
+ * @return boolean TRUE if okay, FALSE if $server_payload isn't set.
+ *
+ * @uses XML_RPC_Server::createServerPayload(),
+ * XML_RPC_Server::$server_headers
+ */
+ function createServerHeaders()
+ {
+ if (!$this->server_payload) {
+ return false;
+ }
+ $this->server_headers = 'Content-Length: '
+ . strlen($this->server_payload) . "\r\n"
+ . 'Content-Type: text/xml;'
+ . ' charset=' . $this->encoding;
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ function verifySignature($in, $sig)
+ {
+ for ($i = 0; $i < sizeof($sig); $i++) {
+ // check each possible signature in turn
+ $cursig = $sig[$i];
+ if (sizeof($cursig) == $in->getNumParams() + 1) {
+ $itsOK = 1;
+ for ($n = 0; $n < $in->getNumParams(); $n++) {
+ $p = $in->getParam($n);
+ // print "<!-- $p -->\n";
+ if ($p->kindOf() == 'scalar') {
+ $pt = $p->scalartyp();
+ } else {
+ $pt = $p->kindOf();
+ }
+ // $n+1 as first type of sig is return type
+ if ($pt != $cursig[$n+1]) {
+ $itsOK = 0;
+ $pno = $n+1;
+ $wanted = $cursig[$n+1];
+ $got = $pt;
+ break;
+ }
+ }
+ if ($itsOK) {
+ return array(1);
+ }
+ }
+ }
+ if (isset($wanted)) {
+ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
+ } else {
+ $allowed = array();
+ foreach ($sig as $val) {
+ end($val);
+ $allowed[] = key($val);
+ }
+ $allowed = array_unique($allowed);
+ $last = count($allowed) - 1;
+ if ($last > 0) {
+ $allowed[$last] = 'or ' . $allowed[$last];
+ }
+ return array(0,
+ 'Signature permits ' . implode(', ', $allowed)
+ . ' parameters but the request had '
+ . $in->getNumParams());
+ }
+ }
+
+ /**
+ * @return object a new XML_RPC_Response object
+ *
+ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding
+ */
+ function parseRequest($data = '')
+ {
+ global $XML_RPC_xh,
+ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml,
+ $XML_RPC_defencoding, $XML_RPC_Server_dmap;
+
+ if ($data == '') {
+ $data = file_get_contents("php://input");
+ $this->client_data = $data;
+ }
+
+ $this->encoding = XML_RPC_Message::getEncoding($data);
+ $parser_resource = xml_parser_create($this->encoding);
+ $parser = (int) $parser_resource;
+
+ $XML_RPC_xh[$parser] = array();
+ $XML_RPC_xh[$parser]['cm'] = 0;
+ $XML_RPC_xh[$parser]['isf'] = 0;
+ $XML_RPC_xh[$parser]['params'] = array();
+ $XML_RPC_xh[$parser]['method'] = '';
+ $XML_RPC_xh[$parser]['stack'] = array();
+ $XML_RPC_xh[$parser]['valuestack'] = array();
+
+ $plist = '';
+
+ // decompose incoming XML into request structure
+
+ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
+ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
+ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
+ if (!xml_parse($parser_resource, $data, 1)) {
+ // return XML error as a faultCode
+ $r = new XML_RPC_Response(0,
+ $XML_RPC_errxml+xml_get_error_code($parser_resource),
+ sprintf('XML error: %s at line %d',
+ xml_error_string(xml_get_error_code($parser_resource)),
+ xml_get_current_line_number($parser_resource)));
+ xml_parser_free($parser_resource);
+ } elseif ($XML_RPC_xh[$parser]['isf']>1) {
+ $r = new XML_RPC_Response(0,
+ $XML_RPC_err['invalid_request'],
+ $XML_RPC_str['invalid_request']
+ . ': '
+ . $XML_RPC_xh[$parser]['isf_reason']);
+ xml_parser_free($parser_resource);
+ } else {
+ xml_parser_free($parser_resource);
+ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']);
+ // now add parameters in
+ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) {
+ // print '<!-- ' . $XML_RPC_xh[$parser]['params'][$i]. "-->\n";
+ $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n";
+ $m->addParam($XML_RPC_xh[$parser]['params'][$i]);
+ }
+
+ if ($this->debug) {
+ XML_RPC_Server_debugmsg($plist);
+ }
+
+ // now to deal with the method
+ $methName = $XML_RPC_xh[$parser]['method'];
+ if (strpos($methName, 'system.') === 0) {
+ $dmap = $XML_RPC_Server_dmap;
+ $sysCall = 1;
+ } else {
+ $dmap = $this->dmap;
+ $sysCall = 0;
+ }
+
+ if (isset($dmap[$methName]['function'])
+ && is_string($dmap[$methName]['function'])
+ && strpos($dmap[$methName]['function'], '::') !== false)
+ {
+ $dmap[$methName]['function'] =
+ explode('::', $dmap[$methName]['function']);
+ }
+
+ if (isset($dmap[$methName]['function'])
+ && is_callable($dmap[$methName]['function']))
+ {
+ // dispatch if exists
+ if (isset($dmap[$methName]['signature'])) {
+ $sr = $this->verifySignature($m,
+ $dmap[$methName]['signature'] );
+ }
+ if (!isset($dmap[$methName]['signature']) || $sr[0]) {
+ // if no signature or correct signature
+ if ($sysCall) {
+ $r = call_user_func($dmap[$methName]['function'], $this, $m);
+ } else {
+ $r = call_user_func($dmap[$methName]['function'], $m);
+ }
+ if (!is_a($r, 'XML_RPC_Response')) {
+ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'],
+ $XML_RPC_str['not_response_object']);
+ }
+ } else {
+ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
+ $XML_RPC_str['incorrect_params']
+ . ': ' . $sr[1]);
+ }
+ } else {
+ // else prepare error response
+ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'],
+ $XML_RPC_str['unknown_method']);
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * Echos back the input packet as a string value
+ *
+ * @return void
+ *
+ * Useful for debugging.
+ */
+ function echoInput()
+ {
+ $r = new XML_RPC_Response(0);
+ $r->xv = new XML_RPC_Value("'Aha said I: '" . $this->client_data, 'string');
+ print $r->serialize();
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?>
diff --git a/src/etc/inc/zeromq.inc b/src/etc/inc/zeromq.inc
new file mode 100644
index 0000000..6b513d3
--- /dev/null
+++ b/src/etc/inc/zeromq.inc
@@ -0,0 +1,340 @@
+<?php
+/*
+ zeromq.inc
+ part of the pfSense project (https://www.pfsense.org)
+ Copyright 2010 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+define('ZEROMQ_AUTH_FAIL', 'authfail');
+define('ZEROMQ_TRUE', 'true');
+define('ZEROMQ_FASLE', 'false');
+
+$do_not_include_config_gui_inc = true;
+require_once("auth.inc");
+
+//$debug = true;
+
+/* zeromq_send: Send a message to a member node */
+function zeromq_send($protocol = "tcp", $ipaddress = "127.0.0.1", $port = "8888",
+ $method, $params, $username, $password) {
+
+ global $debug;
+
+ /* Set calling function and auth information */
+ $xmlparams = array(
+ $username,
+ $password,
+ $method,
+ $params
+ );
+
+ /* Create new queue object */
+ $queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ, "MySock1");
+ $queue->connect("{$protocol}://{$ipaddress}:{$port}");
+
+ /* Assign socket 1 to the queue, send and receive */
+ $result = $queue->send(serialize($xmlparams))->recv();
+
+ /* xmlrpc_params_to_php() the result and return */
+ $unserializedresult = unserialize($result);
+
+ /* Return the result to the caller */
+ return $unserializedresult;
+}
+
+function zeromq_server($protocol = "tcp", $ipaddress = "127.0.0.1", $port = "8888") {
+ global $debug;
+ if (!$ipaddress || !$port) {
+ if ($debug) {
+ echo "ERROR: You must pass, proto, ipaddress and port\n";
+ }
+ return;
+ }
+ if ($debug) {
+ echo "Creating ZMQSocket()\n";
+ }
+ $server = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REP);
+ if ($debug) {
+ echo "Binding to {$protocol}://{$ipaddress}:{$port}\n";
+ }
+ $server->bind("{$protocol}://{$ipaddress}:{$port}");
+ if ($debug) {
+ echo "Entering while() loop\n";
+ }
+ while ($msg = $server->recv()) {
+ // Convert the XML to a PHP array
+ $message = unserialize($msg);
+ if ($debug) {
+ echo "Message received:\n";
+ print_r($message);
+ }
+ switch ($message[2]) {
+ case "pfsense.exec_shell":
+ $function_to_call = "exec_shell_zeromq";
+ break;
+ case "pfsense.exec_php":
+ $function_to_call = "exec_php_zeromq";
+ break;
+ case "pfsense.filter_configure":
+ $function_to_call = "filter_configure_zeromq";
+ break;
+ case "pfsense.interfaces_carp_configure":
+ $function_to_call = "interfaces_carp_configure_zeromq";
+ break;
+ case "pfsense.backup_config_section":
+ $function_to_call = "backup_config_section_zeromq";
+ break;
+ case "pfsense.restore_config_section":
+ $function_to_call = "restore_config_section_zeromq";
+ break;
+ case "pfsense.merge_config_section":
+ $function_to_call = "merge_config_section_zeromq";
+ break;
+ case "pfsense.merge_installedpackages_section_zeromq":
+ $function_to_call = "merge_installedpackages_section_zeromq";
+ break;
+ case "pfsense.check_firmware_version":
+ $function_to_call = "check_firmware_version_zeromq";
+ break;
+ case "pfsense.reboot":
+ $function_to_call = "reboot_zeromq";
+ break;
+ case "pfsense.get_notices":
+ $function_to_call = "get_notices_zeromq";
+ break;
+ }
+ if (!$function_to_call) {
+ if ($debug) {
+ echo "ERROR: Could not find a function to call";
+ }
+ return;
+ } else {
+ if ($debug) {
+ echo "Invoking function {$message[2]}()\n;";
+ }
+ }
+ /* Call function that is being invoked */
+ $result = $function_to_call($message);
+ /* echo back the result */
+ $server->send($result);
+ }
+}
+
+function zeromq_auth($params) {
+ global $config, $g, $debug;
+
+ $username = $params[0];
+ $passwd = $params[1];
+
+ $user = getUserEntry($username);
+ if (!$user) {
+ if ($debug) {
+ echo "Could not locate user $username with getUserEntry()\n";
+ }
+ return false;
+ }
+
+ if (is_account_disabled($username) || is_account_expired($username)) {
+ if ($debug) {
+ echo "Returning account expired/disabled\n";
+ }
+ return false;
+ }
+
+ if ($user['password']) {
+ $passwd = crypt($passwd, $user['password']);
+ if ($passwd == $user['password']) {
+ return true;
+ }
+ }
+
+ if ($user['md5-hash']) {
+ $passwd = md5($passwd);
+ if ($passwd == $user['md5-hash']) {
+ return true;
+ }
+ }
+
+ if ($debug) {
+ echo "zeromq_auth() fall through == false\n";
+ }
+
+ return false;
+}
+
+function exec_php_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ if ($debug) {
+ echo "Auth failed in exec_shell_zeromq()\n";
+ }
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $exec_php = $params[3];
+ if ($debug) {
+ echo "Running exec_php_zeromq(): {$exec_php}\n";
+ }
+ eval($exec_php);
+ if ($toreturn) {
+ return serialize($toreturn);
+ } else {
+ return ZEROMQ_FASLE;
+ }
+}
+
+function exec_shell_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ if ($debug) {
+ echo "Auth failed in exec_shell_zeromq()\n";
+ }
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $shell_cmd = $params[3];
+ if ($debug) {
+ echo "Running exec_shell_zeromq(): {$shell_cmd}\n";
+ }
+ mwexec($shell_cmd);
+ return ZEROMQ_FASLE;
+}
+
+function backup_config_section_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $val = array_intersect_key($config, array_flip($params[3]));
+ return serialize($val);
+}
+
+function restore_config_section_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $config = array_merge($config, $params[3]);
+ $mergedkeys = implode(",", array_keys($params[3]));
+ write_config(sprintf(gettext("Merged in config (%s sections) from ZeroMQ client."), $mergedkeys));
+ return ZEROMQ_FASLE;
+}
+
+function merge_installedpackages_section_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $config['installedpackages'] = array_merge($config['installedpackages'], $params[0]);
+ $mergedkeys = implode(",", array_keys($params[3]));
+ write_config(sprintf(gettext("Merged in config (%s sections) from ZeroMQ client."), $mergedkeys));
+ return ZEROMQ_FASLE;
+}
+
+function merge_config_section_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ $config = array_merge_recursive_unique($config, $params[0]);
+ $mergedkeys = implode(",", array_keys($params[3]));
+ write_config("Merged in config ({$mergedkeys} sections) from ZeroMQ client.");
+ return ZEROMQ_FASLE;
+}
+
+function filter_configure_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ filter_configure();
+ system_routing_configure();
+ setup_gateways_monitor();
+ relayd_configure();
+ require_once("openvpn.inc");
+ openvpn_resync_all();
+ services_dhcpd_configure();
+ if (isset($config['dnsmasq']['enable'])) {
+ services_dnsmasq_configure();
+ } elseif (isset($config['unbound']['enable'])) {
+ services_unbound_configure();
+ }
+ local_sync_accounts();
+ return ZEROMQ_FASLE;
+}
+
+function interfaces_carp_configure_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ interfaces_sync_setup();
+ interfaces_vips_configure();
+ return ZEROMQ_FASLE;
+}
+
+function check_firmware_version_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ return serialize(check_firmware_version(false));
+}
+
+function reboot_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ mwexec_bg("/etc/rc.reboot");
+ return ZEROMQ_FASLE;
+}
+
+function get_notices_zeromq($raw_params) {
+ global $config, $g, $debug;
+ $params = $raw_params;
+ if (zeromq_auth($raw_params) == false) {
+ return ZEROMQ_AUTH_FAIL;
+ }
+ if (!function_exists("get_notices")) {
+ require("notices.inc");
+ }
+ if (!$params) {
+ $toreturn = get_notices();
+ } else {
+ $toreturn = get_notices($params);
+ }
+ return serialize($toreturn);
+}
+
+?>
diff --git a/src/etc/inetd.conf b/src/etc/inetd.conf
new file mode 100644
index 0000000..0ff37ae
--- /dev/null
+++ b/src/etc/inetd.conf
@@ -0,0 +1 @@
+tftp-proxy dgram udp wait root /usr/libexec/tftp-proxy tftp-proxy \ No newline at end of file
diff --git a/src/etc/login.conf b/src/etc/login.conf
new file mode 100644
index 0000000..1e61a9f
--- /dev/null
+++ b/src/etc/login.conf
@@ -0,0 +1,317 @@
+# login.conf - login class capabilities database.
+#
+# Remember to rebuild the database after each change to this file:
+#
+# cap_mkdb /etc/login.conf
+#
+# This file controls resource limits, accounting limits and
+# default user environment settings.
+#
+# $FreeBSD: src/etc/login.conf,v 1.34.2.6 2002/07/02 20:06:18 dillon Exp $
+#
+
+# Default settings effectively disable resource limits, see the
+# examples below for a starting point to enable them.
+
+# defaults
+# These settings are used by login(1) by default for classless users
+# Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
+
+default:\
+ :passwd_format=md5:\
+ :copyright=/etc/COPYRIGHT:\
+ :welcome=/dev/null:\
+ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES:\
+ :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\
+ :nologin=/var/run/nologin:\
+ :cputime=unlimited:\
+ :datasize=unlimited:\
+ :stacksize=unlimited:\
+ :memorylocked=unlimited:\
+ :memoryuse=unlimited:\
+ :filesize=unlimited:\
+ :coredumpsize=unlimited:\
+ :openfiles=unlimited:\
+ :maxproc=unlimited:\
+ :sbsize=unlimited:\
+ :vmemoryuse=unlimited:\
+ :idletime=unlimited:\
+ :priority=0:\
+ :ignoretime@:\
+ :umask=022:
+
+
+#
+# A collection of common class names - forward them all to 'default'
+# (login would normally do this anyway, but having a class name
+# here suppresses the diagnostic)
+#
+standard:\
+ :tc=default:
+xuser:\
+ :tc=default:
+staff:\
+ :tc=default:
+daemon:\
+ :tc=default:
+news:\
+ :tc=default:
+dialer:\
+ :tc=default:
+
+#
+# Root can always login
+#
+# N.B. login_getpwclass(3) will use this entry for the root account,
+# in preference to 'default'.
+root:\
+ :ignorenologin:\
+ :tc=default:
+
+#
+# Russian Users Accounts. Setup proper environment variables.
+#
+russian|Russian Users Accounts:\
+ :charset=KOI8-R:\
+ :lang=ru_RU.KOI8-R:\
+ :tc=default:
+
+
+######################################################################
+######################################################################
+##
+## Example entries
+##
+######################################################################
+######################################################################
+
+## Example defaults
+## These settings are used by login(1) by default for classless users
+## Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
+#
+#default:\
+# :cputime=infinity:\
+# :datasize-cur=22M:\
+# :stacksize-cur=8M:\
+# :memorylocked-cur=10M:\
+# :memoryuse-cur=30M:\
+# :filesize=infinity:\
+# :coredumpsize=infinity:\
+# :maxproc-cur=64:\
+# :openfiles-cur=64:\
+# :priority=0:\
+# :requirehome@:\
+# :umask=022:\
+# :tc=auth-defaults:
+#
+#
+##
+## standard - standard user defaults
+##
+#standard:\
+# :copyright=/etc/COPYRIGHT:\
+# :welcome=/etc/motd:\
+# :setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\
+# :path=~/bin /bin /usr/bin /usr/local/bin:\
+# :manpath=/usr/share/man /usr/local/man:\
+# :nologin=/var/run/nologin:\
+# :cputime=1h30m:\
+# :datasize=8M:\
+# :vmemoryuse=100M:\
+# :stacksize=2M:\
+# :memorylocked=4M:\
+# :memoryuse=8M:\
+# :filesize=8M:\
+# :coredumpsize=8M:\
+# :openfiles=24:\
+# :maxproc=32:\
+# :priority=0:\
+# :requirehome:\
+# :passwordtime=90d:\
+# :umask=002:\
+# :ignoretime@:\
+# :tc=default:
+#
+#
+##
+## users of X (needs more resources!)
+##
+#xuser:\
+# :manpath=/usr/share/man /usr/X11R6/man /usr/local/man:\
+# :cputime=4h:\
+# :datasize=12M:\
+# :vmemoryuse=infinity:\
+# :stacksize=4M:\
+# :filesize=8M:\
+# :memoryuse=16M:\
+# :openfiles=32:\
+# :maxproc=48:\
+# :tc=standard:
+#
+#
+##
+## Staff users - few restrictions and allow login anytime
+##
+#staff:\
+# :ignorenologin:\
+# :ignoretime:\
+# :requirehome@:\
+# :accounted@:\
+# :path=~/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :umask=022:\
+# :tc=standard:
+#
+#
+##
+## root - fallback for root logins
+##
+#root:\
+# :path=~/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :cputime=infinity:\
+# :datasize=infinity:\
+# :stacksize=infinity:\
+# :memorylocked=infinity:\
+# :memoryuse=infinity:\
+# :filesize=infinity:\
+# :coredumpsize=infinity:\
+# :openfiles=infinity:\
+# :maxproc=infinity:\
+# :memoryuse-cur=32M:\
+# :maxproc-cur=64:\
+# :openfiles-cur=1024:\
+# :priority=0:\
+# :requirehome@:\
+# :umask=022:\
+# :tc=auth-root-defaults:
+#
+#
+##
+## Settings used by /etc/rc
+##
+#daemon:\
+# :coredumpsize@:\
+# :coredumpsize-cur=0:\
+# :datasize=infinity:\
+# :datasize-cur@:\
+# :maxproc=512:\
+# :maxproc-cur@:\
+# :memoryuse-cur=64M:\
+# :memorylocked-cur=64M:\
+# :openfiles=1024:\
+# :openfiles-cur@:\
+# :stacksize=16M:\
+# :stacksize-cur@:\
+# :tc=default:
+#
+#
+##
+## Settings used by news subsystem
+##
+#news:\
+# :path=/usr/local/news/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :cputime=infinity:\
+# :filesize=128M:\
+# :datasize-cur=64M:\
+# :stacksize-cur=32M:\
+# :coredumpsize-cur=0:\
+# :maxmemorysize-cur=128M:\
+# :memorylocked=32M:\
+# :maxproc=128:\
+# :openfiles=256:\
+# :tc=default:
+#
+#
+##
+## The dialer class should be used for a dialup PPP/SLIP accounts
+## Welcome messages/news suppressed
+##
+#dialer:\
+# :hushlogin:\
+# :requirehome@:\
+# :cputime=unlimited:\
+# :filesize=2M:\
+# :datasize=2M:\
+# :stacksize=4M:\
+# :coredumpsize=0:\
+# :memoryuse=4M:\
+# :memorylocked=1M:\
+# :maxproc=16:\
+# :openfiles=32:\
+# :tc=standard:
+#
+#
+##
+## Site full-time 24/7 PPP/SLIP connections
+## - no time accounting, restricted to access via dialin lines
+##
+#site:\
+# :ignoretime:\
+# :passwordtime@:\
+# :refreshtime@:\
+# :refreshperiod@:\
+# :sessionlimit@:\
+# :autodelete@:\
+# :expireperiod@:\
+# :graceexpire@:\
+# :gracetime@:\
+# :warnexpire@:\
+# :warnpassword@:\
+# :idletime@:\
+# :sessiontime@:\
+# :daytime@:\
+# :weektime@:\
+# :monthtime@:\
+# :warntime@:\
+# :accounted@:\
+# :tc=dialer:\
+# :tc=staff:
+#
+#
+##
+## Example standard accounting entries for subscriber levels
+##
+#
+#subscriber|Subscribers:\
+# :accounted:\
+# :refreshtime=180d:\
+# :refreshperiod@:\
+# :sessionlimit@:\
+# :autodelete=30d:\
+# :expireperiod=180d:\
+# :graceexpire=7d:\
+# :gracetime=10m:\
+# :warnexpire=7d:\
+# :warnpassword=7d:\
+# :idletime=30m:\
+# :sessiontime=4h:\
+# :daytime=6h:\
+# :weektime=40h:\
+# :monthtime=120h:\
+# :warntime=4h:\
+# :tc=standard:
+#
+#
+##
+## Subscriber accounts. These accounts have their login times
+## accounted and have access limits applied.
+##
+#subppp|PPP Subscriber Accounts:\
+# :tc=dialer:\
+# :tc=subscriber:
+#
+#
+#subslip|SLIP Subscriber Accounts:\
+# :tc=dialer:\
+# :tc=subscriber:
+#
+#
+#subshell|Shell Subscriber Accounts:\
+# :tc=subscriber:
+#
+##
+## If you want some of the accounts to use traditional UNIX DES based
+## password hashes.
+##
+#des_users:\
+# :passwd_format=des:\
+# :tc=default:
diff --git a/src/etc/master.passwd b/src/etc/master.passwd
new file mode 100644
index 0000000..bb46954
--- /dev/null
+++ b/src/etc/master.passwd
@@ -0,0 +1,29 @@
+# $FreeBSD: src/etc/master.passwd,v 1.39 2004/08/01 21:33:47 markm Exp $
+#
+root:$1$9ZCIHWSF$/6MpmsZXSQbkARathg3cX1:0:0::0:0:Charlie &:/root:/bin/sh
+toor:*:0:0::0:0:Bourne-again Superuser:/root:
+daemon:*:1:1::0:0:Owner of many system processes:/root:/usr/sbin/nologin
+operator:*:2:5::0:0:System &:/:/usr/sbin/nologin
+bin:*:3:7::0:0:Binaries Commands and Source:/:/usr/sbin/nologin
+tty:*:4:65533::0:0:Tty Sandbox:/:/usr/sbin/nologin
+kmem:*:5:65533::0:0:KMem Sandbox:/:/usr/sbin/nologin
+games:*:7:13::0:0:Games pseudo-user:/usr/games:/usr/sbin/nologin
+news:*:8:8::0:0:News Subsystem:/:/usr/sbin/nologin
+man:*:9:9::0:0:Mister Man Pages:/usr/share/man:/usr/sbin/nologin
+sshd:*:22:22::0:0:Secure Shell Daemon:/var/empty:/usr/sbin/nologin
+smmsp:*:25:25::0:0:Sendmail Submission User:/var/spool/clientmqueue:/usr/sbin/nologin
+mailnull:*:26:26::0:0:Sendmail Default User:/var/spool/mqueue:/usr/sbin/nologin
+bind:*:53:53::0:0:Bind Sandbox:/:/usr/sbin/nologin
+unbound:*:59:59::0:0:Unbound DNS Resolver:/var/unbound:/usr/sbin/nologin
+proxy:*:62:62::0:0:Packet Filter pseudo-user:/nonexistent:/usr/sbin/nologin
+_pflogd:*:64:64::0:0:pflogd privsep user:/var/empty:/usr/sbin/nologin
+www:*:80:80::0:0:World Wide Web Owner:/nonexistent:/usr/sbin/nologin
+nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin
+dhcpd:*:1002:1002::0:0:DHCP Daemon:/nonexistent:/sbin/nologin
+admin:$1$9ZCIHWSF$/6MpmsZXSQbkARathg3cX1:0:0::0:0:Admin User:/root:/bin/sh
+_dhcp:*:65:65::0:0:dhcp programs:/var/empty:/usr/sbin/nologin
+_isakmpd:*:68:68::0:0:isakmpd privsep:/var/empty:/sbin/nologin
+uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/local/libexec/uucp/uucico
+pop:*:68:6::0:0:Post Office Owner:/nonexistent:/usr/sbin/nologin
+_ntp:*:123:123::0:0:NTP daemon:/var/empty:/sbin/nologin
+_relayd:*:913:913::0:0:Relay Daemon:/var/empty:/usr/sbin/nologin
diff --git a/src/etc/motd b/src/etc/motd
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/etc/motd
diff --git a/src/etc/mtree/BSD.local.dist b/src/etc/mtree/BSD.local.dist
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/etc/mtree/BSD.local.dist
diff --git a/src/etc/networks b/src/etc/networks
new file mode 100644
index 0000000..92982b5
--- /dev/null
+++ b/src/etc/networks
@@ -0,0 +1,17 @@
+# $FreeBSD: src/etc/networks,v 1.3 1999/08/27 23:23:42 peter Exp $
+# @(#)networks 5.1 (Berkeley) 6/30/90
+#
+# Your Local Networks Database
+#
+your-net 127 # your comment
+your-netmask 255.255.255 # subnet mask for your-net
+
+#
+# Your subnets
+#
+subnet1 127.0.1 alias1 # comment 1
+subnet2 127.0.2 alias2 # comment 2
+
+#
+# Internet networks (from nic.ddn.mil)
+#
diff --git a/src/etc/passwd b/src/etc/passwd
new file mode 100644
index 0000000..040f3e5
--- /dev/null
+++ b/src/etc/passwd
@@ -0,0 +1,26 @@
+root:*:0:0:Charlie &:/root:/bin/sh
+toor:*:0:0:Bourne-again Superuser:/root:
+daemon:*:1:1:Owner of many system processes:/root:/usr/sbin/nologin
+operator:*:2:5:System &:/:/usr/sbin/nologin
+bin:*:3:7:Binaries Commands and Source:/:/usr/sbin/nologin
+tty:*:4:65533:Tty Sandbox:/:/usr/sbin/nologin
+kmem:*:5:65533:KMem Sandbox:/:/usr/sbin/nologin
+games:*:7:13:Games pseudo-user:/usr/games:/usr/sbin/nologin
+news:*:8:8:News Subsystem:/:/usr/sbin/nologin
+man:*:9:9:Mister Man Pages:/usr/share/man:/usr/sbin/nologin
+sshd:*:22:22:Secure Shell Daemon:/var/empty:/usr/sbin/nologin
+smmsp:*:25:25:Sendmail Submission User:/var/spool/clientmqueue:/usr/sbin/nologin
+mailnull:*:26:26:Sendmail Default User:/var/spool/mqueue:/usr/sbin/nologin
+bind:*:53:53:Bind Sandbox:/:/usr/sbin/nologin
+unbound:*:59:59:Unbound DNS Resolver:/var/unbound:/usr/sbin/nologin
+proxy:*:62:62:Packet Filter pseudo-user:/nonexistent:/usr/sbin/nologin
+_pflogd:*:64:64:pflogd privsep user:/var/empty:/usr/sbin/nologin
+uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/local/libexec/uucp/uucico
+pop:*:68:6::0:0:Post Office Owner:/nonexistent:/usr/sbin/nologin
+www:*:80:80:World Wide Web Owner:/nonexistent:/usr/sbin/nologin
+nobody:*:65534:65534:Unprivileged user:/nonexistent:/usr/sbin/nologin
+distcc:*:1001:1001:Distcc:/home/distcc:/sbin/nologin
+dhcpd:*:1002:1002:DHCP Daemon:/nonexistent:/sbin/nologin
+admin:*:0:0:Admin User:/home/admin:/bin/sh
+_ntp:*:123:123:NTP daemon:/var/empty:/sbin/nologin
+_relayd:*:913:913:Relay Daemon:/var/empty:/usr/sbin/nologin
diff --git a/src/etc/pf.os b/src/etc/pf.os
new file mode 100644
index 0000000..56c7cbf
--- /dev/null
+++ b/src/etc/pf.os
@@ -0,0 +1,698 @@
+# $FreeBSD: stable/10/etc/pf.os 244096 2012-12-10 20:52:52Z delphij $
+# $OpenBSD: pf.os,v 1.26 2012/08/03 12:25:16 jsg Exp $
+# passive OS fingerprinting
+# -------------------------
+#
+# SYN signatures. Those signatures work for SYN packets only (duh!).
+#
+# (C) Copyright 2000-2003 by Michal Zalewski <lcamtuf@coredump.cx>
+# (C) Copyright 2003 by Mike Frantzen <frantzen@w4g.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# This fingerprint database is adapted from Michal Zalewski's p0f passive
+# operating system package. The last database sync was from a Nov 3 2003
+# p0f.fp.
+#
+#
+# Each line in this file specifies a single fingerprint. Please read the
+# information below carefully before attempting to append any signatures
+# reported as UNKNOWN to this file to avoid mistakes.
+#
+# We use the following set metrics for fingerprinting:
+#
+# - Window size (WSS) - a highly OS dependent setting used for TCP/IP
+# performance control (max. amount of data to be sent without ACK).
+# Some systems use a fixed value for initial packets. On other
+# systems, it is a multiple of MSS or MTU (MSS+40). In some rare
+# cases, the value is just arbitrary.
+#
+# NEW SIGNATURE: if p0f reported a special value of 'Snn', the number
+# appears to be a multiple of MSS (MSS*nn); a special value of 'Tnn'
+# means it is a multiple of MTU ((MSS+40)*nn). Unless you notice the
+# value of nn is not fixed (unlikely), just copy the Snn or Tnn token
+# literally. If you know this device has a simple stack and a fixed
+# MTU, you can however multiply S value by MSS, or T value by MSS+40,
+# and put it instead of Snn or Tnn.
+#
+# If WSS otherwise looks like a fixed value (for example a multiple
+# of two), or if you can confirm the value is fixed, please quote
+# it literally. If there's no apparent pattern in WSS chosen, you
+# should consider wildcarding this value.
+#
+# - Overall packet size - a function of all IP and TCP options and bugs.
+#
+# NEW SIGNATURE: Copy this value literally.
+#
+# - Initial TTL - We check the actual TTL of a received packet. It can't
+# be higher than the initial TTL, and also shouldn't be dramatically
+# lower (maximum distance is defined as 40 hops).
+#
+# NEW SIGNATURE: *Never* copy TTL from a p0f-reported signature literally.
+# You need to determine the initial TTL. The best way to do it is to
+# check the documentation for a remote system, or check its settings.
+# A fairly good method is to simply round the observed TTL up to
+# 32, 64, 128, or 255, but it should be noted that some obscure devices
+# might not use round TTLs (in particular, some shoddy appliances use
+# "original" initial TTL settings). If not sure, you can see how many
+# hops you're away from the remote party with traceroute or mtr.
+#
+# - Don't fragment flag (DF) - some modern OSes set this to implement PMTU
+# discovery. Others do not bother.
+#
+# NEW SIGNATURE: Copy this value literally.
+#
+# - Maximum segment size (MSS) - this setting is usually link-dependent. P0f
+# uses it to determine link type of the remote host.
+#
+# NEW SIGNATURE: Always wildcard this value, except for rare cases when
+# you have an appliance with a fixed value, know the system supports only
+# a very limited number of network interface types, or know the system
+# is using a value it pulled out of nowhere. Specific unique MSS
+# can be used to tell Google crawlbots from the rest of the population.
+#
+# - Window scaling (WSCALE) - this feature is used to scale WSS.
+# It extends the size of a TCP/IP window to 32 bits. Some modern
+# systems implement this feature.
+#
+# NEW SIGNATURE: Observe several signatures. Initial WSCALE is often set
+# to zero or other low value. There's usually no need to wildcard this
+# parameter.
+#
+# - Timestamp - some systems that implement timestamps set them to
+# zero in the initial SYN. This case is detected and handled appropriately.
+#
+# - Selective ACK permitted - a flag set by systems that implement
+# selective ACK functionality.
+#
+# - The sequence of TCP all options (MSS, window scaling, selective ACK
+# permitted, timestamp, NOP). Other than the options previously
+# discussed, p0f also checks for timestamp option (a silly
+# extension to broadcast your uptime ;-), NOP options (used for
+# header padding) and sackOK option (selective ACK feature).
+#
+# NEW SIGNATURE: Copy the sequence literally.
+#
+# To wildcard any value (except for initial TTL or TCP options), replace
+# it with '*'. You can also use a modulo operator to match any values
+# that divide by nnn - '%nnn'.
+#
+# Fingerprint entry format:
+#
+# wwww:ttt:D:ss:OOO...:OS:Version:Subtype:Details
+#
+# wwww - window size (can be *, %nnn, Snn or Tnn). The special values
+# "S" and "T" which are a multiple of MSS or a multiple of MTU
+# respectively.
+# ttt - initial TTL
+# D - don't fragment bit (0 - not set, 1 - set)
+# ss - overall SYN packet size
+# OOO - option value and order specification (see below)
+# OS - OS genre (Linux, Solaris, Windows)
+# Version - OS Version (2.0.27 on x86, etc)
+# Subtype - OS subtype or patchlevel (SP3, lo0)
+# details - Generic OS details
+#
+# If OS genre starts with '*', p0f will not show distance, link type
+# and timestamp data. It is useful for userland TCP/IP stacks of
+# network scanners and so on, where many settings are randomized or
+# bogus.
+#
+# If OS genre starts with @, it denotes an approximate hit for a group
+# of operating systems (signature reporting still enabled in this case).
+# Use this feature at the end of this file to catch cases for which
+# you don't have a precise match, but can tell it's Windows or FreeBSD
+# or whatnot by looking at, say, flag layout alone.
+#
+# Option block description is a list of comma or space separated
+# options in the order they appear in the packet:
+#
+# N - NOP option
+# Wnnn - window scaling option, value nnn (or * or %nnn)
+# Mnnn - maximum segment size option, value nnn (or * or %nnn)
+# S - selective ACK OK
+# T - timestamp
+# T0 - timestamp with a zero value
+#
+# To denote no TCP options, use a single '.'.
+#
+# Please report any additions to this file, or any inaccuracies or
+# problems spotted, to the maintainers: lcamtuf@coredump.cx,
+# frantzen@openbsd.org and bugs@openbsd.org with a tcpdump packet
+# capture of the relevant SYN packet(s)
+#
+# A test and submission page is available at
+# http://lcamtuf.coredump.cx/p0f-help/
+#
+#
+# WARNING WARNING WARNING
+# -----------------------
+#
+# Do not add a system X as OS Y just because NMAP says so. It is often
+# the case that X is a NAT firewall. While nmap is talking to the
+# device itself, p0f is fingerprinting the guy behind the firewall
+# instead.
+#
+# When in doubt, use common sense, don't add something that looks like
+# a completely different system as Linux or FreeBSD or LinkSys router.
+# Check DNS name, establish a connection to the remote host and look
+# at SYN+ACK - does it look similar?
+#
+# Some users tweak their TCP/IP settings - enable or disable RFC1323
+# functionality, enable or disable timestamps or selective ACK,
+# disable PMTU discovery, change MTU and so on. Always compare a new rule
+# to other fingerprints for this system, and verify the system isn't
+# "customized" before adding it. It is OK to add signature variants
+# caused by a commonly used software (personal firewalls, security
+# packages, etc), but it makes no sense to try to add every single
+# possible /proc/sys/net/ipv4 tweak on Linux or so.
+#
+# KEEP IN MIND: Some packet firewalls configured to normalize outgoing
+# traffic (OpenBSD pf with "scrub" enabled, for example) will, well,
+# normalize packets. Signatures will not correspond to the originating
+# system (and probably not quite to the firewall either).
+#
+# NOTE: Try to keep this file in some reasonable order, from most to
+# least likely systems. This will speed up operation. Also keep most
+# generic and broad rules near the end.
+#
+
+##########################
+# Standard OS signatures #
+##########################
+
+# ----------------- AIX ---------------------
+
+# AIX is first because its signatures are close to NetBSD, MacOS X and
+# Linux 2.0, but it uses a fairly rare MSSes, at least sometimes...
+# This is a shoddy hack, though.
+
+45046:64:0:44:M*: AIX:4.3::AIX 4.3
+16384:64:0:44:M512: AIX:4.3:2-3:AIX 4.3.2 and earlier
+
+16384:64:0:60:M512,N,W%2,N,N,T: AIX:4.3:3:AIX 4.3.3-5.2
+16384:64:0:60:M512,N,W%2,N,N,T: AIX:5.1-5.2::AIX 4.3.3-5.2
+32768:64:0:60:M512,N,W%2,N,N,T: AIX:4.3:3:AIX 4.3.3-5.2
+32768:64:0:60:M512,N,W%2,N,N,T: AIX:5.1-5.2::AIX 4.3.3-5.2
+65535:64:0:60:M512,N,W%2,N,N,T: AIX:4.3:3:AIX 4.3.3-5.2
+65535:64:0:60:M512,N,W%2,N,N,T: AIX:5.1-5.2::AIX 4.3.3-5.2
+65535:64:0:64:M*,N,W1,N,N,T,N,N,S: AIX:5.3:ML1:AIX 5.3 ML1
+
+# ----------------- Linux -------------------
+
+# S1:64:0:44:M*:A: Linux:1.2::Linux 1.2.x (XXX quirks support)
+512:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x
+16384:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x
+
+# Endian snafu! Nelson says "ha-ha":
+2:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x (MkLinux) on Mac
+64:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x (MkLinux) on Mac
+
+
+S4:64:1:60:M1360,S,T,N,W0: Linux:google::Linux (Google crawlbot)
+
+S2:64:1:60:M*,S,T,N,W0: Linux:2.4::Linux 2.4 (big boy)
+S3:64:1:60:M*,S,T,N,W0: Linux:2.4:.18-21:Linux 2.4.18 and newer
+S4:64:1:60:M*,S,T,N,W0: Linux:2.4::Linux 2.4/2.6 <= 2.6.7
+S4:64:1:60:M*,S,T,N,W0: Linux:2.6:.1-7:Linux 2.4/2.6 <= 2.6.7
+
+S4:64:1:60:M*,S,T,N,W5: Linux:2.6::Linux 2.6 (newer, 1)
+S4:64:1:60:M*,S,T,N,W6: Linux:2.6::Linux 2.6 (newer, 2)
+S4:64:1:60:M*,S,T,N,W7: Linux:2.6::Linux 2.6 (newer, 3)
+T4:64:1:60:M*,S,T,N,W7: Linux:2.6::Linux 2.6 (newer, 4)
+
+S10:64:1:60:M*,S,T,N,W4: Linux:3.0::Linux 3.0
+
+S3:64:1:60:M*,S,T,N,W1: Linux:2.5::Linux 2.5 (sometimes 2.4)
+S4:64:1:60:M*,S,T,N,W1: Linux:2.5-2.6::Linux 2.5/2.6
+S3:64:1:60:M*,S,T,N,W2: Linux:2.5::Linux 2.5 (sometimes 2.4)
+S4:64:1:60:M*,S,T,N,W2: Linux:2.5::Linux 2.5 (sometimes 2.4)
+
+S20:64:1:60:M*,S,T,N,W0: Linux:2.2:20-25:Linux 2.2.20 and newer
+S22:64:1:60:M*,S,T,N,W0: Linux:2.2::Linux 2.2
+S11:64:1:60:M*,S,T,N,W0: Linux:2.2::Linux 2.2
+
+# Popular cluster config scripts disable timestamps and
+# selective ACK:
+S4:64:1:48:M1460,N,W0: Linux:2.4:cluster:Linux 2.4 in cluster
+
+# This needs to be investigated. On some systems, WSS
+# is selected as a multiple of MTU instead of MSS. I got
+# many submissions for this for many late versions of 2.4:
+T4:64:1:60:M1412,S,T,N,W0: Linux:2.4::Linux 2.4 (late, uncommon)
+
+# This happens only over loopback, but let's make folks happy:
+32767:64:1:60:M16396,S,T,N,W0: Linux:2.4:lo0:Linux 2.4 (local)
+S8:64:1:60:M3884,S,T,N,W0: Linux:2.2:lo0:Linux 2.2 (local)
+
+# Opera visitors:
+16384:64:1:60:M*,S,T,N,W0: Linux:2.2:Opera:Linux 2.2 (Opera?)
+32767:64:1:60:M*,S,T,N,W0: Linux:2.4:Opera:Linux 2.4 (Opera?)
+
+# Some fairly common mods:
+S4:64:1:52:M*,N,N,S,N,W0: Linux:2.4:ts:Linux 2.4 w/o timestamps
+S22:64:1:52:M*,N,N,S,N,W0: Linux:2.2:ts:Linux 2.2 w/o timestamps
+
+
+# ----------------- FreeBSD -----------------
+
+16384:64:1:44:M*: FreeBSD:2.0-2.2::FreeBSD 2.0-4.2
+16384:64:1:44:M*: FreeBSD:3.0-3.5::FreeBSD 2.0-4.2
+16384:64:1:44:M*: FreeBSD:4.0-4.2::FreeBSD 2.0-4.2
+16384:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.4::FreeBSD 4.4
+
+1024:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.4::FreeBSD 4.4
+
+57344:64:1:44:M*: FreeBSD:4.6-4.8:noRFC1323:FreeBSD 4.6-4.8 (no RFC1323)
+57344:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.6-4.9::FreeBSD 4.6-4.9
+
+32768:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.8-4.11::FreeBSD 4.8-5.1 (or MacOS X)
+32768:64:1:60:M*,N,W0,N,N,T: FreeBSD:5.0-5.1::FreeBSD 4.8-5.1 (or MacOS X)
+65535:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.8-4.11::FreeBSD 4.8-5.2 (or MacOS X)
+65535:64:1:60:M*,N,W0,N,N,T: FreeBSD:5.0-5.2::FreeBSD 4.8-5.2 (or MacOS X)
+65535:64:1:60:M*,N,W1,N,N,T: FreeBSD:4.7-4.11::FreeBSD 4.7-5.2
+65535:64:1:60:M*,N,W1,N,N,T: FreeBSD:5.0-5.2::FreeBSD 4.7-5.2
+
+# XXX need quirks support
+# 65535:64:1:60:M*,N,W0,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (1)
+# 65535:64:1:60:M*,N,W1,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (2)
+# 65535:64:1:60:M*,N,W2,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (3)
+# 65535:64:1:44:M*:Z:FreeBSD:5.2::FreeBSD 5.2 (no RFC1323)
+
+# 16384:64:1:60:M*,N,N,N,N,N,N,T:FreeBSD:4.4:noTS:FreeBSD 4.4 (w/o timestamps)
+
+# ----------------- NetBSD ------------------
+
+16384:64:0:60:M*,N,W0,N,N,T: NetBSD:1.3::NetBSD 1.3
+65535:64:0:60:M*,N,W0,N,N,T0: NetBSD:1.6:opera:NetBSD 1.6 (Opera)
+16384:64:0:60:M*,N,W0,N,N,T0: NetBSD:1.6::NetBSD 1.6
+16384:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6:df:NetBSD 1.6 (DF)
+65535:64:1:60:M*,N,W1,N,N,T0: NetBSD:1.6::NetBSD 1.6W-current (DF)
+65535:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6::NetBSD 1.6X (DF)
+32768:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6:randomization:NetBSD 1.6ZH-current (w/ ip_id randomization)
+
+# ----------------- OpenBSD -----------------
+
+16384:64:0:60:M*,N,W0,N,N,T: OpenBSD:2.6::NetBSD 1.3 (or OpenBSD 2.6)
+16384:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.8::OpenBSD 3.0-4.8
+16384:64:0:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.8:no-df:OpenBSD 3.0-4.8 (scrub no-df)
+57344:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.3-4.0::OpenBSD 3.3-4.0
+57344:64:0:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.3-4.0:no-df:OpenBSD 3.3-4.0 (scrub no-df)
+
+65535:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.0:opera:OpenBSD 3.0-4.0 (Opera)
+
+16384:64:1:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9::OpenBSD 4.9
+16384:64:0:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9:no-df:OpenBSD 4.9 (scrub no-df)
+
+# ----------------- Solaris -----------------
+
+S17:64:1:64:N,W3,N,N,T0,N,N,S,M*: Solaris:8:RFC1323:Solaris 8 RFC1323
+S17:64:1:48:N,N,S,M*: Solaris:8::Solaris 8
+S17:255:1:44:M*: Solaris:2.5-2.7::Solaris 2.5 to 7
+
+S6:255:1:44:M*: Solaris:2.6-2.7::Solaris 2.6 to 7
+S23:255:1:44:M*: Solaris:2.5:1:Solaris 2.5.1
+S34:64:1:48:M*,N,N,S: Solaris:2.9::Solaris 9
+S44:255:1:44:M*: Solaris:2.7::Solaris 7
+
+4096:64:0:44:M1460: SunOS:4.1::SunOS 4.1.x
+
+S34:64:1:52:M*,N,W0,N,N,S: Solaris:10:beta:Solaris 10 (beta)
+32850:64:1:64:M*,N,N,T,N,W1,N,N,S: Solaris:10::Solaris 10 1203
+
+# ----------------- IRIX --------------------
+
+49152:64:0:44:M*: IRIX:6.4::IRIX 6.4
+61440:64:0:44:M*: IRIX:6.2-6.5::IRIX 6.2-6.5
+49152:64:0:52:M*,N,W2,N,N,S: IRIX:6.5:RFC1323:IRIX 6.5 (RFC1323)
+49152:64:0:52:M*,N,W3,N,N,S: IRIX:6.5:RFC1323:IRIX 6.5 (RFC1323)
+
+61440:64:0:48:M*,N,N,S: IRIX:6.5:12-21:IRIX 6.5.12 - 6.5.21
+49152:64:0:48:M*,N,N,S: IRIX:6.5:15-21:IRIX 6.5.15 - 6.5.21
+
+49152:60:0:64:M*,N,W2,N,N,T,N,N,S: IRIX:6.5:IP27:IRIX 6.5 IP27
+
+
+# ----------------- Tru64 -------------------
+
+32768:64:1:48:M*,N,W0: Tru64:4.0::Tru64 4.0 (or OS/2 Warp 4)
+32768:64:0:48:M*,N,W0: Tru64:5.0::Tru64 5.0
+8192:64:0:44:M1460: Tru64:5.1:noRFC1323:Tru64 6.1 (no RFC1323) (or QNX 6)
+61440:64:0:48:M*,N,W0: Tru64:5.1a:JP4:Tru64 v5.1a JP4 (or OpenVMS 7.x on Compaq 5.x stack)
+
+# ----------------- OpenVMS -----------------
+
+6144:64:1:60:M*,N,W0,N,N,T: OpenVMS:7.2::OpenVMS 7.2 (Multinet 4.4 stack)
+
+# ----------------- MacOS -------------------
+
+# XXX Need EOL tcp opt support
+# S2:255:1:48:M*,W0,E:.:MacOS:8.6 classic
+
+# XXX some of these use EOL too
+16616:255:1:48:M*,W0: MacOS:7.3-7.6:OTTCP:MacOS 7.3-8.6 (OTTCP)
+16616:255:1:48:M*,W0: MacOS:8.0-8.6:OTTCP:MacOS 7.3-8.6 (OTTCP)
+16616:255:1:48:M*,N,N,N: MacOS:8.1-8.6:OTTCP:MacOS 8.1-8.6 (OTTCP)
+32768:255:1:48:M*,W0,N: MacOS:9.0-9.2::MacOS 9.0-9.2
+65535:255:1:48:M*,N,N,N,N: MacOS:9.1::MacOS 9.1 (OT 2.7.4)
+
+
+# ----------------- Windows -----------------
+
+# Windows TCP/IP stack is a mess. For most recent XP, 2000 and
+# even 98, the patchlevel, not the actual OS version, is more
+# relevant to the signature. They share the same code, so it would
+# seem. Luckily for us, almost all Windows 9x boxes have an
+# awkward MSS of 536, which I use to tell one from another
+# in most difficult cases.
+
+8192:32:1:44:M*: Windows:3.11::Windows 3.11 (Tucows)
+S44:64:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:95::Windows 95
+8192:128:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:95:b:Windows 95b
+
+# There were so many tweaking tools and so many stack versions for
+# Windows 98 it is no longer possible to tell them from each other
+# without some very serious research. Until then, there's an insane
+# number of signatures, for your amusement:
+
+S44:32:1:48:M*,N,N,S: Windows:98:lowTTL:Windows 98 (low TTL)
+8192:32:1:48:M*,N,N,S: Windows:98:lowTTL:Windows 98 (low TTL)
+%8192:64:1:48:M536,N,N,S: Windows:98::Windows 98
+%8192:128:1:48:M536,N,N,S: Windows:98::Windows 98
+S4:64:1:48:M*,N,N,S: Windows:98::Windows 98
+S6:64:1:48:M*,N,N,S: Windows:98::Windows 98
+S12:64:1:48:M*,N,N,S: Windows:98::Windows 98
+T30:64:1:64:M1460,N,W0,N,N,T0,N,N,S: Windows:98::Windows 98
+32767:64:1:48:M*,N,N,S: Windows:98::Windows 98
+37300:64:1:48:M*,N,N,S: Windows:98::Windows 98
+46080:64:1:52:M*,N,W3,N,N,S: Windows:98:RFC1323:Windows 98 (RFC1323)
+65535:64:1:44:M*: Windows:98:noSack:Windows 98 (no sack)
+S16:128:1:48:M*,N,N,S: Windows:98::Windows 98
+S16:128:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:98::Windows 98
+S26:128:1:48:M*,N,N,S: Windows:98::Windows 98
+T30:128:1:48:M*,N,N,S: Windows:98::Windows 98
+32767:128:1:52:M*,N,W0,N,N,S: Windows:98::Windows 98
+60352:128:1:48:M*,N,N,S: Windows:98::Windows 98
+60352:128:1:64:M*,N,W2,N,N,T0,N,N,S: Windows:98::Windows 98
+
+# What's with 1414 on NT?
+T31:128:1:44:M1414: Windows:NT:4.0:Windows NT 4.0 SP6a
+64512:128:1:44:M1414: Windows:NT:4.0:Windows NT 4.0 SP6a
+8192:128:1:44:M*: Windows:NT:4.0:Windows NT 4.0 (older)
+
+# Windows XP and 2000. Most of the signatures that were
+# either dubious or non-specific (no service pack data)
+# were deleted and replaced with generics at the end.
+
+65535:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4, XP SP1
+65535:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP4, XP SP1
+%8192:128:1:48:M*,N,N,S: Windows:2000:SP2+:Windows 2000 SP2, XP SP1 (seldom 98 4.10.2222)
+%8192:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP2, XP SP1 (seldom 98 4.10.2222)
+S20:128:1:48:M*,N,N,S: Windows:2000::Windows 2000/XP SP3
+S20:128:1:48:M*,N,N,S: Windows:XP:SP3:Windows 2000/XP SP3
+S45:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4, XP SP 1
+S45:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP4, XP SP 1
+40320:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4
+
+S6:128:1:48:M*,N,N,S: Windows:2000:SP2:Windows XP, 2000 SP2+
+S6:128:1:48:M*,N,N,S: Windows:XP::Windows XP, 2000 SP2+
+S12:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows XP SP1
+S44:128:1:48:M*,N,N,S: Windows:2000:SP3:Windows Pro SP1, 2000 SP3
+S44:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows Pro SP1, 2000 SP3
+64512:128:1:48:M*,N,N,S: Windows:2000:SP3:Windows SP1, 2000 SP3
+64512:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows SP1, 2000 SP3
+32767:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows SP1, 2000 SP4
+32767:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows SP1, 2000 SP4
+
+8192:128:1:52:M*,N,W2,N,N,S: Windows:Vista::Windows Vista/7
+
+# Odds, ends, mods:
+
+S52:128:1:48:M1260,N,N,S: Windows:2000:cisco:Windows XP/2000 via Cisco
+S52:128:1:48:M1260,N,N,S: Windows:XP:cisco:Windows XP/2000 via Cisco
+65520:128:1:48:M*,N,N,S: Windows:XP::Windows XP bare-bone
+16384:128:1:52:M536,N,W0,N,N,S: Windows:2000:ZoneAlarm:Windows 2000 w/ZoneAlarm?
+2048:255:0:40:.: Windows:.NET::Windows .NET Enterprise Server
+
+44620:64:0:48:M*,N,N,S: Windows:ME::Windows ME no SP (?)
+S6:255:1:48:M536,N,N,S: Windows:95:winsock2:Windows 95 winsock 2
+32768:32:1:52:M1460,N,W0,N,N,S: Windows:2003:AS:Windows 2003 AS
+
+
+# No need to be more specific, it passes:
+# *:128:1:48:M*,N,N,S:U:-Windows:XP/2000 while downloading (leak!) XXX quirk
+# there is an equiv similar generic sig w/o the quirk
+
+# ----------------- HP/UX -------------------
+
+32768:64:1:44:M*: HP-UX:B.10.20::HP-UX B.10.20
+32768:64:0:48:M*,W0,N: HP-UX:11.0::HP-UX 11.0
+32768:64:1:48:M*,W0,N: HP-UX:11.10::HP-UX 11.0 or 11.11
+32768:64:1:48:M*,W0,N: HP-UX:11.11::HP-UX 11.0 or 11.11
+
+# Whoa. Hardcore WSS.
+0:64:0:48:M*,W0,N: HP-UX:B.11.00:A:HP-UX B.11.00 A (RFC1323)
+
+# ----------------- RiscOS ------------------
+
+# We don't yet support the ?12 TCP option
+#16384:64:1:68:M1460,N,W0,N,N,T,N,N,?12: RISCOS:3.70-4.36::RISC OS 3.70-4.36
+12288:32:0:44:M536: RISC OS:3.70:4.10:RISC OS 3.70 inet 4.10
+
+# XXX quirk
+# 4096:64:1:56:M1460,N,N,T:T: RISC OS:3.70:freenet:RISC OS 3.70 freenet 2.00
+
+
+
+# ----------------- BSD/OS ------------------
+
+# Once again, power of two WSS is also shared by MacOS X with DF set
+8192:64:1:60:M1460,N,W0,N,N,T: BSD/OS:3.1::BSD/OS 3.1-4.3 (or MacOS X 10.2 w/DF)
+8192:64:1:60:M1460,N,W0,N,N,T: BSD/OS:4.0-4.3::BSD/OS 3.1-4.3 (or MacOS X 10.2)
+
+
+# ---------------- NewtonOS -----------------
+
+4096:64:0:44:M1420: NewtonOS:2.1::NewtonOS 2.1
+
+# ---------------- NeXTSTEP -----------------
+
+S4:64:0:44:M1024: NeXTSTEP:3.3::NeXTSTEP 3.3
+S8:64:0:44:M512: NeXTSTEP:3.3::NeXTSTEP 3.3
+
+# ------------------ BeOS -------------------
+
+1024:255:0:48:M*,N,W0: BeOS:5.0-5.1::BeOS 5.0-5.1
+12288:255:0:44:M1402: BeOS:5.0::BeOS 5.0.x
+
+# ------------------ OS/400 -----------------
+
+8192:64:1:60:M1440,N,W0,N,N,T: OS/400:VR4::OS/400 VR4/R5
+8192:64:1:60:M1440,N,W0,N,N,T: OS/400:VR5::OS/400 VR4/R5
+4096:64:1:60:M1440,N,W0,N,N,T: OS/400:V4R5:CF67032:OS/400 V4R5 + CF67032
+
+# XXX quirk
+# 28672:64:0:44:M1460:A:OS/390:?
+
+# ------------------ ULTRIX -----------------
+
+16384:64:0:40:.: ULTRIX:4.5::ULTRIX 4.5
+
+# ------------------- QNX -------------------
+
+S16:64:0:44:M512: QNX:::QNX demodisk
+
+# ------------------ Novell -----------------
+
+16384:128:1:44:M1460: Novell:NetWare:5.0:Novel Netware 5.0
+6144:128:1:44:M1460: Novell:IntranetWare:4.11:Novell IntranetWare 4.11
+6144:128:1:44:M1368: Novell:BorderManager::Novell BorderManager ?
+
+6144:128:1:52:M*,W0,N,S,N,N: Novell:Netware:6:Novell Netware 6 SP3
+
+
+# ----------------- SCO ------------------
+S3:64:1:60:M1460,N,W0,N,N,T: SCO:UnixWare:7.1:SCO UnixWare 7.1
+S17:64:1:60:M1380,N,W0,N,N,T: SCO:UnixWare:7.1:SCO UnixWare 7.1.3 MP3
+S23:64:1:44:M1380: SCO:OpenServer:5.0:SCO OpenServer 5.0
+
+# ------------------- DOS -------------------
+
+2048:255:0:44:M536: DOS:WATTCP:1.05:DOS Arachne via WATTCP/1.05
+T2:255:0:44:M984: DOS:WATTCP:1.05Arachne:Arachne via WATTCP/1.05 (eepro)
+
+# ------------------ OS/2 -------------------
+
+S56:64:0:44:M512: OS/2:4::OS/2 4
+28672:64:0:44:M1460: OS/2:4::OS/2 Warp 4.0
+
+# ----------------- TOPS-20 -----------------
+
+# Another hardcore MSS, one of the ACK leakers hunted down.
+# XXX QUIRK 0:64:0:44:M1460:A:TOPS-20:version 7
+0:64:0:44:M1460: TOPS-20:7::TOPS-20 version 7
+
+# ----------------- FreeMiNT ----------------
+
+S44:255:0:44:M536: FreeMiNT:1:16A:FreeMiNT 1 patch 16A (Atari)
+
+# ------------------ AMIGA ------------------
+
+# XXX TCP option 12
+# S32:64:1:56:M*,N,N,S,N,N,?12:.:AMIGA:3.9 BB2 with Miami stack
+
+# ------------------ Plan9 ------------------
+
+65535:255:0:48:M1460,W0,N: Plan9:4::Plan9 edition 4
+
+# ----------------- AMIGAOS -----------------
+
+16384:64:1:48:M1560,N,N,S: AMIGAOS:3.9::AMIGAOS 3.9 BB2 MiamiDX
+
+###########################################
+# Appliance / embedded / other signatures #
+###########################################
+
+# ---------- Firewalls / routers ------------
+
+S12:64:1:44:M1460: @Checkpoint:::Checkpoint (unknown 1)
+S12:64:1:48:N,N,S,M1460: @Checkpoint:::Checkpoint (unknown 2)
+4096:32:0:44:M1460: ExtremeWare:4.x::ExtremeWare 4.x
+
+# XXX TCP option 12
+# S32:64:0:68:M512,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO w/Checkpoint NG FP3
+# S16:64:0:68:M1024,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO 3.7 build 026
+
+S4:64:1:60:W0,N,S,T,M1460: FortiNet:FortiGate:50:FortiNet FortiGate 50
+
+8192:64:1:44:M1460: Eagle:::Eagle Secure Gateway
+
+S52:128:1:48:M1260,N,N,N,N: LinkSys:WRV54G::LinkSys WRV54G VPN router
+
+
+
+# ------- Switches and other stuff ----------
+
+4128:255:0:44:M*: Cisco:::Cisco Catalyst 3500, 7500 etc
+S8:255:0:44:M*: Cisco:12008::Cisco 12008
+60352:128:1:64:M1460,N,W2,N,N,T,N,N,S: Alteon:ACEswitch::Alteon ACEswitch
+64512:128:1:44:M1370: Nortel:Contivity Client::Nortel Conectivity Client
+
+
+# ---------- Caches and whatnots ------------
+
+S4:64:1:52:M1460,N,N,S,N,W0: AOL:web cache::AOL web cache
+
+32850:64:1:64:N,W1,N,N,T,N,N,S,M*: NetApp:5.x::NetApp Data OnTap 5.x
+16384:64:1:64:M1460,N,N,S,N,W0,N: NetApp:5.3:1:NetApp 5.3.1
+65535:64:0:64:M1460,N,N,S,N,W*,N,N,T: NetApp:5.3-5.5::NetApp 5.3-5.5
+65535:64:0:60:M1460,N,W0,N,N,T: NetApp:CacheFlow::NetApp CacheFlow
+8192:64:1:64:M1460,N,N,S,N,W0,N,N,T: NetApp:5.2:1:NetApp NetCache 5.2.1
+20480:64:1:64:M1460,N,N,S,N,W0,N,N,T: NetApp:4.1::NetApp NetCache4.1
+
+65535:64:0:60:M1460,N,W0,N,N,T: CacheFlow:4.1::CacheFlow CacheOS 4.1
+8192:64:0:60:M1380,N,N,N,N,N,N,T: CacheFlow:1.1::CacheFlow CacheOS 1.1
+
+S4:64:0:48:M1460,N,N,S: Cisco:Content Engine::Cisco Content Engine
+
+27085:128:0:40:.: Dell:PowerApp cache::Dell PowerApp (Linux-based)
+
+65535:255:1:48:N,W1,M1460: Inktomi:crawler::Inktomi crawler
+S1:255:1:60:M1460,S,T,N,W0: LookSmart:ZyBorg::LookSmart ZyBorg
+
+16384:255:0:40:.: Proxyblocker:::Proxyblocker (what's this?)
+
+65535:255:0:48:M*,N,N,S: Redline:::Redline T|X 2200
+
+32696:128:0:40:M1460: Spirent:Avalanche::Spirent Web Avalanche HTTP benchmarking engine
+
+# ----------- Embedded systems --------------
+
+S9:255:0:44:M536: PalmOS:Tungsten:C:PalmOS Tungsten C
+S5:255:0:44:M536: PalmOS:3::PalmOS 3/4
+S5:255:0:44:M536: PalmOS:4::PalmOS 3/4
+S4:255:0:44:M536: PalmOS:3:5:PalmOS 3.5
+2948:255:0:44:M536: PalmOS:3:5:PalmOS 3.5.3 (Handera)
+S29:255:0:44:M536: PalmOS:5::PalmOS 5.0
+16384:255:0:44:M1398: PalmOS:5.2:Clie:PalmOS 5.2 (Clie)
+S14:255:0:44:M1350: PalmOS:5.2:Treo:PalmOS 5.2.1 (Treo)
+
+S23:64:1:64:N,W1,N,N,T,N,N,S,M1460: SymbianOS:7::SymbianOS 7
+
+8192:255:0:44:M1460: SymbianOS:6048::Symbian OS 6048 (Nokia 7650?)
+8192:255:0:44:M536: SymbianOS:9210::Symbian OS (Nokia 9210?)
+S22:64:1:56:M1460,T,S: SymbianOS:P800::Symbian OS ? (SE P800?)
+S36:64:1:56:M1360,T,S: SymbianOS:6600::Symbian OS 60xx (Nokia 6600?)
+
+
+# Perhaps S4?
+5840:64:1:60:M1452,S,T,N,W1: Zaurus:3.10::Zaurus 3.10
+
+32768:128:1:64:M1460,N,W0,N,N,T0,N,N,S: PocketPC:2002::PocketPC 2002
+
+S1:255:0:44:M346: Contiki:1.1:rc0:Contiki 1.1-rc0
+
+4096:128:0:44:M1460: Sega:Dreamcast:3.0:Sega Dreamcast Dreamkey 3.0
+T5:64:0:44:M536: Sega:Dreamcast:HKT-3020:Sega Dreamcast HKT-3020 (browser disc 51027)
+S22:64:1:44:M1460: Sony:PS2::Sony Playstation 2 (SOCOM?)
+
+S12:64:0:44:M1452: AXIS:5600:v5.64:AXIS Printer Server 5600 v5.64
+
+3100:32:1:44:M1460: Windows:CE:2.0:Windows CE 2.0
+
+####################
+# Fancy signatures #
+####################
+
+1024:64:0:40:.: *NMAP:syn scan:1:NMAP syn scan (1)
+2048:64:0:40:.: *NMAP:syn scan:2:NMAP syn scan (2)
+3072:64:0:40:.: *NMAP:syn scan:3:NMAP syn scan (3)
+4096:64:0:40:.: *NMAP:syn scan:4:NMAP syn scan (4)
+
+# Requires quirks support
+# 1024:64:0:40:.:A:*NMAP:TCP sweep probe (1)
+# 2048:64:0:40:.:A:*NMAP:TCP sweep probe (2)
+# 3072:64:0:40:.:A:*NMAP:TCP sweep probe (3)
+# 4096:64:0:40:.:A:*NMAP:TCP sweep probe (4)
+
+1024:64:0:60:W10,N,M265,T: *NMAP:OS:1:NMAP OS detection probe (1)
+2048:64:0:60:W10,N,M265,T: *NMAP:OS:2:NMAP OS detection probe (2)
+3072:64:0:60:W10,N,M265,T: *NMAP:OS:3:NMAP OS detection probe (3)
+4096:64:0:60:W10,N,M265,T: *NMAP:OS:4:NMAP OS detection probe (4)
+
+32767:64:0:40:.: *NAST:::NASTsyn scan
+
+# Requires quirks support
+# 12345:255:0:40:.:A:-p0f:sendsyn utility
+
+
+#####################################
+# Generic signatures - just in case #
+#####################################
+
+#*:64:1:60:M*,N,W*,N,N,T: @FreeBSD:4.0-4.9::FreeBSD 4.x/5.x
+#*:64:1:60:M*,N,W*,N,N,T: @FreeBSD:5.0-5.1::FreeBSD 4.x/5.x
+
+*:128:1:52:M*,N,W0,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W0,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W*,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W*,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:64:M*,N,W0,N,N,T0,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323)
+*:128:1:64:M*,N,W0,N,N,T0,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323)
+*:128:1:64:M*,N,W*,N,N,T0,N,N,S: @Windows:XP:RFC1323:Windows XP (RFC1323, w+)
+*:128:1:48:M536,N,N,S: @Windows:98::Windows 98
+*:128:1:48:M*,N,N,S: @Windows:XP::Windows XP/2000
+*:128:1:48:M*,N,N,S: @Windows:2000::Windows XP/2000
+
+
diff --git a/src/etc/pfSense.obsoletedfiles b/src/etc/pfSense.obsoletedfiles
new file mode 100644
index 0000000..cae1bcf
--- /dev/null
+++ b/src/etc/pfSense.obsoletedfiles
@@ -0,0 +1,1018 @@
+/.cvsignore
+/.history
+/RELENG_1_2
+/bin/rcp
+/boot/device.hints_wrap
+/dist
+/etc/auth.conf
+/etc/current-supfile
+/etc/defaults/pccard.conf
+/etc/freebsd-update.conf
+/etc/gnats
+/etc/hostid
+/etc/hosts.lpd
+/etc/inc/cmd_chain.inc
+/etc/inc/lb.inc
+/etc/inc/m0n0
+/etc/inc/regdomain.inc
+/etc/inc/sysctl.inc
+/etc/inc/array_intersect_key.inc
+/etc/isdn
+/etc/locate.rc
+/etc/mail.rc
+/etc/manpath.config
+/etc/mtree/BSD.x11-4.dist
+/etc/mtree/BSD.x11.dist
+/etc/ntp.conf
+/etc/pccard.conf
+/etc/periodic/daily/130.clean-msgs
+/etc/periodic/daily/140.clean-rwho
+/etc/periodic/daily/150.clean-hoststat
+/etc/periodic/daily/220.backup-pkgdb
+/etc/periodic/daily/300.calendar
+/etc/periodic/daily/405.status-ata-raid
+/etc/periodic/daily/430.status-rwho
+/etc/periodic/daily/440.status-mailq
+/etc/periodic/daily/460.status-mail-rejects
+/etc/periodic/daily/470.status-named
+/etc/periodic/daily/480.status-ntpd
+/etc/periodic/daily/500.queuerun
+/etc/periodic/security/460.chkportsum
+/etc/periodic/security/510.ipfdenied
+/etc/periodic/security/600.ip6fwdenied
+/etc/periodic/security/650.ip6fwlimit
+/etc/periodic/weekly/120.clean-kvmdb
+/etc/periodic/weekly/310.locate
+/etc/periodic/weekly/320.whatis
+/etc/periodic/weekly/330.catman
+/etc/periodic/weekly/400.status-pkg
+/etc/pf.conf
+/etc/pfSense.mtree
+/etc/phpshellsessions/cvssync
+/etc/phpshellsessions/restartftphelper
+/etc/ping_hosts.sh
+/etc/portsnap.conf
+/etc/rc.d/amd
+/etc/rc.d/auto_linklocal
+/etc/rc.d/bluetooth
+/etc/rc.d/bthidd
+/etc/rc.d/early.sh
+/etc/rc.d/encswap
+/etc/rc.d/hcsecd
+/etc/rc.d/idmapd
+/etc/rc.d/ike
+/etc/rc.d/ip6fw
+/etc/rc.d/ipxrouted
+/etc/rc.d/isdnd
+/etc/rc.d/kerberos
+/etc/rc.d/kernel
+/etc/rc.d/lpd
+/etc/rc.d/named
+/etc/rc.d/network_ipv6
+/etc/rc.d/nfslocking
+/etc/rc.d/nfsserver
+/etc/rc.d/ntpd
+/etc/rc.d/othermta
+/etc/rc.d/pccard
+/etc/rc.d/pcvt
+/etc/rc.d/ramdisk
+/etc/rc.d/ramdisk-own
+/etc/rc.d/rootmfs
+/etc/rc.d/rwho
+/etc/rc.d/sendmail
+/etc/rc.d/swap1
+/etc/rc.d/usbd
+/etc/rc.d/uzip
+/etc/rc.dyndns.storecache
+/etc/rc.firewall6
+/etc/rc.initial_firmware_update
+/etc/rc.linkup.sh
+/etc/rc.parse-isc-dhcpd
+/etc/rc.sendmail
+/etc/rrdtool.core
+/etc/ttys_wrap
+/etc/usbd.conf
+/etc/version_base
+/etc/version_kernel
+/kernels
+/lib/libalias.so.5
+/lib/libalias.so.6
+/lib/libbegemot.so.2
+/lib/libbegemot.so.3
+/lib/libbsdxml.so.2
+/lib/libbsdxml.so.3
+/lib/libbsnmp.so.3
+/lib/libbsnmp.so.4
+/lib/libbsnmp.so.5
+/lib/libc.so.6
+/lib/libcam.so.4
+/lib/libcam.so.5
+/lib/libcrypt.so.3
+/lib/libcrypt.so.4
+/lib/libcrypto.so.4
+/lib/libcrypto.so.5
+/lib/libcrypto.so.6
+/lib/libdevstat.so.5
+/lib/libdevstat.so.6
+/lib/libedit.so.5
+/lib/libedit.so.6
+/lib/libgeom.so.3
+/lib/libgeom.so.4
+/lib/libipsec.so.2
+/lib/libipsec.so.3
+/lib/libipx.so.3
+/lib/libkiconv.so.2
+/lib/libkiconv.so.3
+/lib/libkvm.so.3
+/lib/libkvm.so.4
+/lib/libkvm.so.5
+/lib/libm.so.4
+/lib/libmd.so.3
+/lib/libmd.so.4
+/lib/libmd.so.5
+/lib/libncurses.so.6
+/lib/libncurses.so.7
+/lib/libncursesw.so.7
+/lib/libpcap.so.4
+/lib/libpcap.so.5
+/lib/libpcap.so.7
+/lib/libpthread.so.2
+/lib/libreadline.so.6
+/lib/libreadline.so.7
+/lib/libsbuf.so.3
+/lib/libsbuf.so.4
+/lib/libsbuf.so.5
+/lib/libufs.so.3
+/lib/libufs.so.4
+/lib/libufs.so.5
+/lib/libutil.so.5
+/lib/libutil.so.7
+/lib/libutil.so.8
+/lib/libz.so.3
+/lib/libz.so.4
+/lib/libz.so.5
+/root/latest.tgz.sha256
+/sbin/atacontrol
+/sbin/idmapd
+/sbin/ip6fw
+/sbin/mount_devfs
+/sbin/mount_fdescfs
+/sbin/mount_linsysfs
+/sbin/mount_newnfs
+/sbin/mount_nfs4
+/sbin/mount_procfs
+/sbin/ppp-script
+/scripts/dev_bootstrap.sh
+/touch
+/usr/X11R6
+/usr/bin/addftinfo
+/usr/bin/addr2line
+/usr/bin/afmtodit
+/usr/bin/ar
+/usr/bin/as
+/usr/bin/byacc
+/usr/bin/c89
+/usr/bin/c99
+/usr/bin/cc
+/usr/bin/cpp
+/usr/bin/dig
+/usr/bin/eqn
+/usr/bin/flex
+/usr/bin/flex++
+/usr/bin/gcc
+/usr/bin/gnu-ar
+/usr/bin/gnu-ranlib
+/usr/bin/gprof
+/usr/bin/grn
+/usr/bin/grodvi
+/usr/bin/groff
+/usr/bin/grog
+/usr/bin/grolbp
+/usr/bin/grolj4
+/usr/bin/grops
+/usr/bin/grotty
+/usr/bin/hpftodit
+/usr/bin/indxbib
+/usr/bin/install-info
+/usr/bin/ld
+/usr/bin/lex
+/usr/bin/lex++
+/usr/bin/lint
+/usr/bin/lkbib
+/usr/bin/lookbib
+/usr/bin/mmroff
+/usr/bin/neqn
+/usr/bin/nm
+/usr/bin/nroff
+/usr/bin/nslookup
+/usr/bin/nsupdate
+/usr/bin/ntpq
+/usr/bin/objcopy
+/usr/bin/objdump
+/usr/bin/pfbtops
+/usr/bin/pic
+/usr/bin/post-grohtml
+/usr/bin/pre-grohtml
+/usr/bin/psroff
+/usr/bin/ranlib
+/usr/bin/readelf
+/usr/bin/refer
+/usr/bin/rlogin
+/usr/bin/rsh
+/usr/bin/size
+/usr/bin/soelim
+/usr/bin/strings
+/usr/bin/strip
+/usr/bin/tbl
+/usr/bin/texindex
+/usr/bin/tfmtodit
+/usr/bin/troff
+/usr/bin/yacc
+/usr/bin/yyfix
+/usr/lib/libarchive.so.2
+/usr/lib/libarchive.so.4
+/usr/lib/libarchive.so.5
+/usr/lib/libasn1.so.10
+/usr/lib/libbsm.so.1
+/usr/lib/libbsm.so.2
+/usr/lib/libbz2.so.2
+/usr/lib/libbz2.so.3
+/usr/lib/libc_pic.a
+/usr/lib/libc_r.a
+/usr/lib/libc_r.so
+/usr/lib/libc_r.so.6
+/usr/lib/libcalendar.so.3
+/usr/lib/libcalendar.so.4
+/usr/lib/libcom_err.so.3
+/usr/lib/libcom_err.so.4
+/usr/lib/libdevinfo.so.3
+/usr/lib/libdevinfo.so.4
+/usr/lib/libdialog.so.5
+/usr/lib/libdialog.so.6
+/usr/lib/libdialog.so.7
+/usr/lib/libdisk.a
+/usr/lib/libdwarf.so.1
+/usr/lib/libdwarf.so.2
+/usr/lib/libexec
+/usr/lib/libexec/ftp-proxy
+/usr/lib/libfetch.so.4
+/usr/lib/libfetch.so.5
+/usr/lib/libfl.a
+/usr/lib/libform.so.3
+/usr/lib/libform.so.4
+/usr/lib/libformw.so.4
+/usr/lib/libftpio.a
+/usr/lib/libftpio.so
+/usr/lib/libftpio.so.6
+/usr/lib/libftpio.so.7
+/usr/lib/libftpio.so.8
+/usr/lib/libgcc_pic.a
+/usr/lib/libgnuregex.so.3
+/usr/lib/libgnuregex.so.4
+/usr/lib/libheimntlm.so.10
+/usr/lib/libhistory.so.6
+/usr/lib/libhistory.so.7
+/usr/lib/libhx509.so.10
+/usr/lib/libipx.a
+/usr/lib/libipx.so
+/usr/lib/libkeycap.a
+/usr/lib/libkrb5.so.10
+/usr/lib/libkse.so
+/usr/lib/libkse.so.3
+/usr/lib/libl.a
+/usr/lib/libln.a
+/usr/lib/libmagic.so.2
+/usr/lib/libmagic.so.3
+/usr/lib/libmemstat.so.1
+/usr/lib/libmemstat.so.2
+/usr/lib/libmenu.so.3
+/usr/lib/libmenu.so.4
+/usr/lib/libmenuw.so.4
+/usr/lib/libmp.so.5
+/usr/lib/libmp.so.6
+/usr/lib/libmytinfo.a
+/usr/lib/libmytinfo.so
+/usr/lib/libncp.a
+/usr/lib/libncp.so
+/usr/lib/libncp.so.2
+/usr/lib/libnetgraph.so.2
+/usr/lib/libnetgraph.so.3
+/usr/lib/libopie.so.4
+/usr/lib/libopie.so.5
+/usr/lib/libopie.so.6
+/usr/lib/libpam.so.3
+/usr/lib/libpam.so.4
+/usr/lib/libpanel.so.3
+/usr/lib/libpanel.so.4
+/usr/lib/libpanelw.so.4
+/usr/lib/libpcap.so.4
+/usr/lib/libpmc.so.3
+/usr/lib/libpmc.so.4
+/usr/lib/libproc.so.1
+/usr/lib/libpthread.so.2
+/usr/lib/libradius.so.2
+/usr/lib/libradius.so.3
+/usr/lib/libroken.so.10
+/usr/lib/librpcsvc.so.3
+/usr/lib/librpcsvc.so.4
+/usr/lib/librtld_db.so.1
+/usr/lib/libsmb.so.2
+/usr/lib/libsmb.so.3
+/usr/lib/libssh.a
+/usr/lib/libssh.so
+/usr/lib/libssh.so.3
+/usr/lib/libssh.so.4
+/usr/lib/libssh.so.5
+/usr/lib/libssl.so.4
+/usr/lib/libssl.so.5
+/usr/lib/libssl.so.6
+/usr/lib/libstdc++.a
+/usr/lib/libstdc++.so
+/usr/lib/libstdc++.so.5
+/usr/lib/libstdc++.so.6
+/usr/lib/libsupc++.a
+/usr/lib/libtacplus.so.2
+/usr/lib/libtacplus.so.3
+/usr/lib/libtacplus.so.4
+/usr/lib/libthr.so.2
+/usr/lib/libthread_db.so.2
+/usr/lib/libugidfw.so.2
+/usr/lib/libugidfw.so.3
+/usr/lib/libusb.so.2
+/usr/lib/libusbhid.so.3
+/usr/lib/libvgl.so.4
+/usr/lib/libvgl.so.5
+/usr/lib/libwrap.so.4
+/usr/lib/libwrap.so.5
+/usr/lib/pam_chroot.so.3
+/usr/lib/pam_chroot.so.4
+/usr/lib/pam_deny.so.3
+/usr/lib/pam_deny.so.4
+/usr/lib/pam_echo.so.3
+/usr/lib/pam_echo.so.4
+/usr/lib/pam_exec.so.3
+/usr/lib/pam_exec.so.4
+/usr/lib/pam_ftpusers.so.3
+/usr/lib/pam_ftpusers.so.4
+/usr/lib/pam_group.so.3
+/usr/lib/pam_group.so.4
+/usr/lib/pam_guest.so.3
+/usr/lib/pam_guest.so.4
+/usr/lib/pam_lastlog.so.3
+/usr/lib/pam_lastlog.so.4
+/usr/lib/pam_login_access.so.3
+/usr/lib/pam_login_access.so.4
+/usr/lib/pam_nologin.so.3
+/usr/lib/pam_nologin.so.4
+/usr/lib/pam_opie.so.3
+/usr/lib/pam_opie.so.4
+/usr/lib/pam_opieaccess.so.3
+/usr/lib/pam_opieaccess.so.4
+/usr/lib/pam_passwdqc.so.3
+/usr/lib/pam_passwdqc.so.4
+/usr/lib/pam_permit.so.3
+/usr/lib/pam_permit.so.4
+/usr/lib/pam_radius.so.3
+/usr/lib/pam_radius.so.4
+/usr/lib/pam_rhosts.so.3
+/usr/lib/pam_rhosts.so.4
+/usr/lib/pam_rootok.so.3
+/usr/lib/pam_rootok.so.4
+/usr/lib/pam_securetty.so.3
+/usr/lib/pam_securetty.so.4
+/usr/lib/pam_self.so.3
+/usr/lib/pam_self.so.4
+/usr/lib/pam_ssh.so.3
+/usr/lib/pam_ssh.so.4
+/usr/lib/pam_tacplus.so.3
+/usr/lib/pam_tacplus.so.4
+/usr/lib/pam_unix.so.3
+/usr/lib/pam_unix.so.4
+/usr/lib/private/libunbound.a
+/usr/lib/private/libunbound.so
+/usr/lib/private/libunbound.so.5
+/usr/lib/private/libunbound_p.a
+/usr/lib/snmp_bridge.so.5
+/usr/lib/snmp_hostres.so.4
+/usr/lib/snmp_hostres.so.5
+/usr/lib/snmp_mibII.so.4
+/usr/lib/snmp_mibII.so.5
+/usr/lib/snmp_netgraph.so.4
+/usr/lib/snmp_netgraph.so.5
+/usr/lib/snmp_pf.so.4
+/usr/lib/snmp_pf.so.5
+/usr/libexec/catman.local
+/usr/libexec/cc1
+/usr/libexec/lint1
+/usr/libexec/lint2
+/usr/libexec/make_index
+/usr/local/bin/3gstat
+/usr/local/bin/atareinit
+/usr/local/bin/bsdiff
+/usr/local/bin/bspatch
+/usr/local/bin/c_rehash
+/usr/local/bin/checkreload.sh
+/usr/local/bin/ez-ipupdate
+/usr/local/bin/kill_ghosts.sh
+/usr/local/bin/l2tpd
+/usr/local/bin/lua
+/usr/local/bin/luac
+/usr/local/bin/msntp
+/usr/local/bin/ntp-wait
+/usr/local/bin/ntpd
+/usr/local/bin/ntpdate
+/usr/local/bin/ntpdc
+/usr/local/bin/ntpq
+/usr/local/bin/ntptime
+/usr/local/bin/ntptrace
+/usr/local/bin/openssl
+/usr/local/bin/sntp
+/usr/local/bin/spawn-fcgi
+/usr/local/bin/tickadj
+/usr/local/bin/verifysig
+/usr/local/include
+/usr/local/info
+/usr/local/lib/engines
+/usr/local/lib/engines/lib4758cca.so
+/usr/local/lib/engines/libaep.so
+/usr/local/lib/engines/libatalla.so
+/usr/local/lib/engines/libcapi.so
+/usr/local/lib/engines/libchil.so
+/usr/local/lib/engines/libcswift.so
+/usr/local/lib/engines/libgmp.so
+/usr/local/lib/engines/libgost.so
+/usr/local/lib/engines/libnuron.so
+/usr/local/lib/engines/libpadlock.so
+/usr/local/lib/engines/libsureware.so
+/usr/local/lib/engines/libubsec.so
+/usr/local/lib/event2
+/usr/local/lib/event2/libevent_core-2.0.so.6
+/usr/local/lib/event2/libevent_pthreads-2.0.so.6
+/usr/local/lib/libcrypto.a
+/usr/local/lib/libcrypto.so
+/usr/local/lib/libcrypto.so.8
+/usr/local/lib/libcurl.so.3
+/usr/local/lib/libcurl.so.5
+/usr/local/lib/libcurl.so.6
+/usr/local/lib/libczmq.so.0
+/usr/local/lib/libczmq.so.1
+/usr/local/lib/libdns_sd.so.1
+/usr/local/lib/libevent-1.2.so
+/usr/local/lib/libevent-1.3e.so.1
+/usr/local/lib/libevent-1.4.so.4
+/usr/local/lib/libevtlog.so.0
+/usr/local/lib/libfreetype.so.9
+/usr/local/lib/libglib-2.0.so.0
+/usr/local/lib/libgmodule-2.0.so.0
+/usr/local/lib/libgthread-2.0.so.0
+/usr/local/lib/libhistory.so.5
+/usr/local/lib/libiconv.so.3
+/usr/local/lib/libidn.so.17
+/usr/local/lib/libipsec.so
+/usr/local/lib/libipsec.so.0
+/usr/local/lib/liblber-2.4.so.3
+/usr/local/lib/liblber-2.4.so.7
+/usr/local/lib/liblber-2.4.so.8
+/usr/local/lib/libldap-2.4.so.3
+/usr/local/lib/libldap-2.4.so.7
+/usr/local/lib/libldap-2.4.so.8
+/usr/local/lib/liblua.so
+/usr/local/lib/liblua.so.5
+/usr/local/lib/liblualib.so
+/usr/local/lib/liblualib.so.5
+/usr/local/lib/libmcrypt.so.8
+/usr/local/lib/libmhash.so.2
+/usr/local/lib/libpcre.la
+/usr/local/lib/libpcre.so.0
+/usr/local/lib/libpcrecpp.la
+/usr/local/lib/libpcreposix.la
+/usr/local/lib/libpng.so.5
+/usr/local/lib/libpng.so.6
+/usr/local/lib/libpng15.so.15
+/usr/local/lib/libracoon.so.0
+/usr/local/lib/libreadline.so.5
+/usr/local/lib/libsqlite3.so.8
+/usr/local/lib/libssl.a
+/usr/local/lib/libssl.so
+/usr/local/lib/libssl.so.8
+/usr/local/lib/libsyslog-ng-3.3.5.so
+/usr/local/lib/libsyslog-ng-3.3.8.so
+/usr/local/lib/libsyslog-ng-3.3.9.so
+/usr/local/lib/libsyslog-ng-3.4.7.so
+/usr/local/lib/libsyslog-ng-3.5.4.1.so
+/usr/local/lib/libxml2.so.5
+/usr/local/lib/lighttpd/mod_access.a
+/usr/local/lib/lighttpd/mod_access.la
+/usr/local/lib/lighttpd/mod_accesslog.a
+/usr/local/lib/lighttpd/mod_accesslog.la
+/usr/local/lib/lighttpd/mod_alias.a
+/usr/local/lib/lighttpd/mod_alias.la
+/usr/local/lib/lighttpd/mod_auth.a
+/usr/local/lib/lighttpd/mod_auth.la
+/usr/local/lib/lighttpd/mod_cgi.a
+/usr/local/lib/lighttpd/mod_cgi.la
+/usr/local/lib/lighttpd/mod_cml.a
+/usr/local/lib/lighttpd/mod_cml.la
+/usr/local/lib/lighttpd/mod_compress.a
+/usr/local/lib/lighttpd/mod_compress.la
+/usr/local/lib/lighttpd/mod_dirlisting.a
+/usr/local/lib/lighttpd/mod_dirlisting.la
+/usr/local/lib/lighttpd/mod_evasive.a
+/usr/local/lib/lighttpd/mod_evasive.la
+/usr/local/lib/lighttpd/mod_evhost.a
+/usr/local/lib/lighttpd/mod_evhost.la
+/usr/local/lib/lighttpd/mod_expire.a
+/usr/local/lib/lighttpd/mod_expire.la
+/usr/local/lib/lighttpd/mod_fastcgi.a
+/usr/local/lib/lighttpd/mod_fastcgi.la
+/usr/local/lib/lighttpd/mod_flv_streaming.a
+/usr/local/lib/lighttpd/mod_flv_streaming.la
+/usr/local/lib/lighttpd/mod_indexfile.a
+/usr/local/lib/lighttpd/mod_indexfile.la
+/usr/local/lib/lighttpd/mod_mysql_vhost.a
+/usr/local/lib/lighttpd/mod_mysql_vhost.la
+/usr/local/lib/lighttpd/mod_proxy.a
+/usr/local/lib/lighttpd/mod_proxy.la
+/usr/local/lib/lighttpd/mod_redirect.a
+/usr/local/lib/lighttpd/mod_redirect.la
+/usr/local/lib/lighttpd/mod_rewrite.a
+/usr/local/lib/lighttpd/mod_rewrite.la
+/usr/local/lib/lighttpd/mod_rrdtool.a
+/usr/local/lib/lighttpd/mod_rrdtool.la
+/usr/local/lib/lighttpd/mod_scgi.a
+/usr/local/lib/lighttpd/mod_scgi.la
+/usr/local/lib/lighttpd/mod_secdownload.a
+/usr/local/lib/lighttpd/mod_secdownload.la
+/usr/local/lib/lighttpd/mod_setenv.a
+/usr/local/lib/lighttpd/mod_setenv.la
+/usr/local/lib/lighttpd/mod_simple_vhost.a
+/usr/local/lib/lighttpd/mod_simple_vhost.la
+/usr/local/lib/lighttpd/mod_ssi.a
+/usr/local/lib/lighttpd/mod_ssi.la
+/usr/local/lib/lighttpd/mod_staticfile.a
+/usr/local/lib/lighttpd/mod_staticfile.la
+/usr/local/lib/lighttpd/mod_status.a
+/usr/local/lib/lighttpd/mod_status.la
+/usr/local/lib/lighttpd/mod_trigger_b4_dl.a
+/usr/local/lib/lighttpd/mod_trigger_b4_dl.la
+/usr/local/lib/lighttpd/mod_userdir.a
+/usr/local/lib/lighttpd/mod_userdir.la
+/usr/local/lib/lighttpd/mod_usertrack.a
+/usr/local/lib/lighttpd/mod_usertrack.la
+/usr/local/lib/lighttpd/mod_webdav.a
+/usr/local/lib/lighttpd/mod_webdav.la
+/usr/local/lib/mysql/libmysqlclient.so.15
+/usr/local/lib/mysql/libmysqlclient.so.18
+/usr/local/lib/olsrd_dot_draw.so.0.3
+/usr/local/lib/olsrd_dyn_gw.so.0.4
+/usr/local/lib/olsrd_dyn_gw_plain.so.0.4
+/usr/local/lib/olsrd_httpinfo.so.0.1
+/usr/local/lib/olsrd_mini.so.0.1
+/usr/local/lib/olsrd_nameservice.so.0.2
+/usr/local/lib/olsrd_nameservice.so.0.3
+/usr/local/lib/olsrd_pgraph.so.1.1
+/usr/local/lib/olsrd_power.so.0.3
+/usr/local/lib/olsrd_secure.so.0.5
+/usr/local/lib/olsrd_txtinfo.so.0.1
+/usr/local/lib/php/20060613
+/usr/local/lib/php/20090626
+/usr/local/lib/php/extensions/no-debug-non-zts-20020429
+/usr/local/lib/snmp_regex.la
+/usr/local/lib/snmp_ucd.a
+/usr/local/lib/snmp_ucd.la
+/usr/local/libdata/pkgconfig/libcrypto.pc
+/usr/local/libdata/pkgconfig/libssl.pc
+/usr/local/libdata/pkgconfig/openssl.pc
+/usr/local/livefs
+/usr/local/livefs/lib
+/usr/local/man
+/usr/local/openssl/misc
+/usr/local/openssl/misc/CA.pl
+/usr/local/openssl/misc/CA.sh
+/usr/local/openssl/misc/c_hash
+/usr/local/openssl/misc/c_info
+/usr/local/openssl/misc/c_issuer
+/usr/local/openssl/misc/c_name
+/usr/local/openssl/misc/tsget
+/usr/local/openssl/openssl.cnf.sample
+/usr/local/pkg/carp.xml
+/usr/local/pkg/carp_settings.xml
+/usr/local/pkg/olsrd.xml
+/usr/local/pkg/openntpd.inc
+/usr/local/pkg/openntpd.xml
+/usr/local/pkg/openvpn.xml
+/usr/local/pkg/openvpn_cli.xml
+/usr/local/pkg/openvpn_csc.xml
+/usr/local/pkg/routed
+/usr/local/pkg/routed.inc
+/usr/local/pkg/routed.xml
+/usr/local/pkg/routed/routed.inc
+/usr/local/pkg/routed/routed.xml
+/usr/local/pkg/sasyncd.xml
+/usr/local/sbin/atareinit
+/usr/local/sbin/bpalogin
+/usr/local/sbin/cvs_sync.sh
+/usr/local/sbin/dnsextd
+/usr/local/sbin/dnswatch
+/usr/local/sbin/env4801
+/usr/local/sbin/fping
+/usr/local/sbin/ftpsesame
+/usr/local/sbin/grub-install1
+/usr/local/sbin/ipfw_context
+/usr/local/sbin/kbdcheck
+/usr/local/sbin/mdnsd
+/usr/local/sbin/mini_httpd
+/usr/local/sbin/mpd
+/usr/local/sbin/olsrd
+/usr/local/sbin/pbi_makeport_chroot
+/usr/local/sbin/pbi_pbid
+/usr/local/sbin/pftpx
+/usr/local/sbin/racoon
+/usr/local/sbin/racoon_watch.sh
+/usr/local/sbin/racoonctl
+/usr/local/sbin/reset_slbd.sh
+/usr/local/sbin/sasyncd
+/usr/local/sbin/setkey
+/usr/local/sbin/slbd
+/usr/local/sbin/slbd.sh
+/usr/local/sbin/syslog-ng
+/usr/local/share/aclocal
+/usr/local/share/dict
+/usr/local/share/doc
+/usr/local/share/emacs
+/usr/local/share/examples
+/usr/local/share/java
+/usr/local/share/locale/af
+/usr/local/share/locale/am
+/usr/local/share/locale/ar
+/usr/local/share/locale/az
+/usr/local/share/locale/bg
+/usr/local/share/locale/bn
+/usr/local/share/locale/br
+/usr/local/share/locale/bs
+/usr/local/share/locale/cy
+/usr/local/share/locale/da
+/usr/local/share/locale/de
+/usr/local/share/locale/dk
+/usr/local/share/locale/ee
+/usr/local/share/locale/en_CA
+/usr/local/share/locale/en_GB
+/usr/local/share/locale/es
+/usr/local/share/locale/es_ES
+/usr/local/share/locale/es_MX
+/usr/local/share/locale/et
+/usr/local/share/locale/eu
+/usr/local/share/locale/fa
+/usr/local/share/locale/fr
+/usr/local/share/locale/ga
+/usr/local/share/locale/gu
+/usr/local/share/locale/he
+/usr/local/share/locale/hi
+/usr/local/share/locale/hr
+/usr/local/share/locale/hu
+/usr/local/share/locale/id
+/usr/local/share/locale/is
+/usr/local/share/locale/it
+/usr/local/share/locale/ka
+/usr/local/share/locale/kn
+/usr/local/share/locale/lt
+/usr/local/share/locale/lv
+/usr/local/share/locale/mk
+/usr/local/share/locale/ml
+/usr/local/share/locale/mn
+/usr/local/share/locale/ms
+/usr/local/share/locale/mt
+/usr/local/share/locale/nb
+/usr/local/share/locale/nl
+/usr/local/share/locale/or
+/usr/local/share/locale/pa
+/usr/local/share/locale/pt_BR.ISO8858-1
+/usr/local/share/locale/pt_PT
+/usr/local/share/locale/ru
+/usr/local/share/locale/sq
+/usr/local/share/locale/sr@Latn
+/usr/local/share/locale/sv
+/usr/local/share/locale/ta
+/usr/local/share/locale/th
+/usr/local/share/locale/vi
+/usr/local/share/locale/wa
+/usr/local/share/locale/zh
+/usr/local/share/locale/zh_CN.GB2312
+/usr/local/share/locale/zh_TW.Big5
+/usr/local/share/misc
+/usr/local/share/nls
+/usr/local/share/sgml
+/usr/local/share/skel
+/usr/local/share/xml
+/usr/local/www/auto_complete_helper.js
+/usr/local/www/csrf/csrf-secret.php
+/usr/local/www/datetimepicker.js
+/usr/local/www/dfly-pg.gif
+/usr/local/www/dfuife.cgi
+/usr/local/www/dfuife.css
+/usr/local/www/dfuife.js
+/usr/local/www/diag_dhcp_leases.php
+/usr/local/www/diag_logs_slbd.php
+/usr/local/www/diag_showbogons.php
+/usr/local/www/dom-drag.js
+/usr/local/www/draglist.js
+/usr/local/www/dtree.js
+/usr/local/www/easyrule.inc
+/usr/local/www/exec_raw.php
+/usr/local/www/filter_log.inc
+/usr/local/www/filterparser.php
+/usr/local/www/firewall_nat_server.php
+/usr/local/www/firewall_nat_server_edit.php
+/usr/local/www/firewall_rules_schedule_logic.php
+/usr/local/www/firewall_shaper_edit.php
+/usr/local/www/firewall_shaper_queues_edit.php
+/usr/local/www/fred.png
+/usr/local/www/fred-bg.png
+/usr/local/www/ifstats.cgi
+/usr/local/www/includes/javascript.inc.php
+/usr/local/www/includes/log.inc.php
+/usr/local/www/includes/sajax.class.php
+/usr/local/www/index.html
+/usr/local/www/installer/index.php
+/usr/local/www/installer/installer.php
+/usr/local/www/installer
+/usr/local/www/interfaces_lan.php
+/usr/local/www/interfaces_opt.php
+/usr/local/www/interfaces_ppp.php
+/usr/local/www/interfaces_ppp_edit.php
+/usr/local/www/interfaces_wan.php
+/usr/local/www/interfaces_wlan.inc
+/usr/local/www/interfaces_wlan_scan.php
+/usr/local/www/ip_helper.js
+/usr/local/www/javascript/datetimepicker.js
+/usr/local/www/javascript/diag_backup
+/usr/local/www/javascript/diag_backup/diag_backup.js
+/usr/local/www/javascript/firewall_rules_edit.js
+/usr/local/www/javascript/index/sajax.js
+/usr/local/www/javascript/jquery.js
+/usr/local/www/javascript/jquery/jquery-ui.custom.css
+/usr/local/www/javascript/jquery/jquery-ui.custom.min.js
+/usr/local/www/javascript/NetUtils.js
+/usr/local/www/javascript/scriptaculous/CHANGELOG
+/usr/local/www/javascript/scriptaculous/MIT-LICENSE
+/usr/local/www/javascript/system_advanced
+/usr/local/www/javascript/system_advanced/system_advanced.js
+/usr/local/www/load_balancer_relay_action.php
+/usr/local/www/load_balancer_relay_action_edit.php
+/usr/local/www/load_balancer_relay_protocol.php
+/usr/local/www/load_balancer_relay_protocol_edit.php
+/usr/local/www/m0n0
+/usr/local/www/niftyjsCode.js
+/usr/local/www/pool.js
+/usr/local/www/preload.php
+/usr/local/www/progress.php
+/usr/local/www/row_helper.js
+/usr/local/www/row_helper_dynamic.js
+/usr/local/www/row_toggle.js
+/usr/local/www/rrdtool.core
+/usr/local/www/sajax
+/usr/local/www/sajax/index.sajax.php
+/usr/local/www/services_captiveportal_users.php
+/usr/local/www/services_captiveportal_users_edit.php
+/usr/local/www/services_proxyarp.php
+/usr/local/www/services_proxyarp_edit.php
+/usr/local/www/services_usermanager.php
+/usr/local/www/status_slbd_pool.php
+/usr/local/www/status_slbd_vs.php
+/usr/local/www/system_advanced.php
+/usr/local/www/system_advanced_create_certs.php
+/usr/local/www/system_usermanager_addcert.php
+/usr/local/www/themes/_orange-flow
+/usr/local/www/themes/metallic/images/button_left.gif
+/usr/local/www/themes/metallic/images/button_mid.gif
+/usr/local/www/themes/metallic/images/button_right.gif
+/usr/local/www/themes/metallic/images/misc/plogo_0.gif
+/usr/local/www/themes/metallic/images/misc/plogo_1.gif
+/usr/local/www/themes/metallic/images/misc/plogo_10.gif
+/usr/local/www/themes/metallic/images/misc/plogo_2.gif
+/usr/local/www/themes/metallic/images/misc/plogo_3.gif
+/usr/local/www/themes/metallic/images/misc/plogo_4.gif
+/usr/local/www/themes/metallic/images/misc/plogo_5.gif
+/usr/local/www/themes/metallic/images/misc/plogo_6.gif
+/usr/local/www/themes/metallic/images/misc/plogo_7.gif
+/usr/local/www/themes/metallic/images/misc/plogo_8.gif
+/usr/local/www/themes/metallic/images/misc/plogo_9.gif
+/usr/local/www/themes/nervecenter/images/button_left.gif
+/usr/local/www/themes/nervecenter/images/button_mid.gif
+/usr/local/www/themes/nervecenter/images/button_right.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_0.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_1.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_10.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_2.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_3.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_4.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_5.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_6.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_7.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_8.gif
+/usr/local/www/themes/nervecenter/images/misc/plogo_9.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_0.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_1.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_10.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_2.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_3.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_4.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_5.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_6.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_7.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_8.gif
+/usr/local/www/themes/pfsense-dropdown/images/misc/plogo_9.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_0.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_1.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_10.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_2.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_3.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_4.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_5.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_6.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_7.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_8.gif
+/usr/local/www/themes/pfsense/images/misc/plogo_9.gif
+/usr/local/www/themes/pfsense_ng/all backup 1.css
+/usr/local/www/themes/pfsense_ng/images/background.gif
+/usr/local/www/themes/pfsense_ng/images/background.png
+/usr/local/www/themes/pfsense_ng/images/button_left.gif
+/usr/local/www/themes/pfsense_ng/images/button_mid.gif
+/usr/local/www/themes/pfsense_ng/images/button_right.gif
+/usr/local/www/themes/pfsense_ng/images/horizontal.gif
+/usr/local/www/themes/pfsense_ng/images/menu_down.gif
+/usr/local/www/themes/pfsense_ng/images/metal_bgr.gif
+/usr/local/www/themes/pfsense_ng/images/metal_bgr_red.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_0.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_1.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_10.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_2.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_3.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_4.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_5.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_6.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_7.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_8.gif
+/usr/local/www/themes/pfsense_ng/images/misc/plogo_9.gif
+/usr/local/www/themes/the_wall/images/Thumbs.db
+/usr/local/www/themes/the_wall/images/icons/Thumbs.db
+/usr/local/www/themes/the_wall/images/misc/Thumbs.db
+/usr/local/www/ticker.js
+/usr/local/www/tree-images/Thumbs.db
+/usr/local/www/upload_progress.php
+/usr/local/www/vpn_ipsec_ca.php
+/usr/local/www/vpn_ipsec_ca_edit.php
+/usr/local/www/vpn_ipsec_ca_edit_create_cert.php
+/usr/local/www/vpn_ipsec_edit.php
+/usr/local/www/vpn_openvpn.php
+/usr/local/www/vpn_openvpn_ccd.php
+/usr/local/www/vpn_openvpn_ccd_edit.php
+/usr/local/www/vpn_openvpn_cli.php
+/usr/local/www/vpn_openvpn_cli_edit.php
+/usr/local/www/vpn_openvpn_create_certs.php
+/usr/local/www/vpn_openvpn_crl.php
+/usr/local/www/vpn_openvpn_crl_edit.php
+/usr/local/www/vpn_openvpn_srv.php
+/usr/local/www/vpn_openvpn_srv_edit.php
+/usr/local/www/vpn_pppoe_users.php
+/usr/local/www/vpn_pppoe_users_edit.php
+/usr/local/www/wizards/traffic_shaper_wizard.inc
+/usr/local/www/wizards/traffic_shaper_wizard.xml
+/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc
+/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.xml
+/usr/local/www/wlan_strong_key_generator
+/usr/sbin/arlcontrol
+/usr/sbin/audit
+/usr/sbin/auditd
+/usr/sbin/auditreduce
+/usr/sbin/authpf
+/usr/sbin/clog
+/usr/sbin/config_lock.sh
+/usr/sbin/config_unlock.sh
+/usr/sbin/freebsd-update
+/usr/sbin/ispcvt
+/usr/sbin/local-unbound-setup
+/usr/sbin/manctl
+/usr/sbin/nsupdate
+/usr/sbin/ntp-keygen
+/usr/sbin/ntpd
+/usr/sbin/ntpdate
+/usr/sbin/ntpdc
+/usr/sbin/ntptime
+/usr/sbin/ntptrace
+/usr/sbin/pc-sysinstall/Makefile
+/usr/sbin/pc-sysinstall/Makefile.inc
+/usr/sbin/pc-sysinstall/backend-partmanager/Makefile
+/usr/sbin/pc-sysinstall/backend-partmanager/create-part.sh
+/usr/sbin/pc-sysinstall/backend-partmanager/delete-part.sh
+/usr/sbin/pc-sysinstall/backend-query/Makefile
+/usr/sbin/pc-sysinstall/backend-query/detect-emulation.sh
+/usr/sbin/pc-sysinstall/backend-query/detect-laptop.sh
+/usr/sbin/pc-sysinstall/backend-query/detect-nics.sh
+/usr/sbin/pc-sysinstall/backend-query/disk-info.sh
+/usr/sbin/pc-sysinstall/backend-query/disk-list.sh
+/usr/sbin/pc-sysinstall/backend-query/disk-part.sh
+/usr/sbin/pc-sysinstall/backend-query/enable-net.sh
+/usr/sbin/pc-sysinstall/backend-query/get-packages.sh
+/usr/sbin/pc-sysinstall/backend-query/list-components.sh
+/usr/sbin/pc-sysinstall/backend-query/list-config.sh
+/usr/sbin/pc-sysinstall/backend-query/list-mirrors.sh
+/usr/sbin/pc-sysinstall/backend-query/list-packages.sh
+/usr/sbin/pc-sysinstall/backend-query/list-rsync-backups.sh
+/usr/sbin/pc-sysinstall/backend-query/list-tzones.sh
+/usr/sbin/pc-sysinstall/backend-query/query-langs.sh
+/usr/sbin/pc-sysinstall/backend-query/send-logs.sh
+/usr/sbin/pc-sysinstall/backend-query/set-mirror.sh
+/usr/sbin/pc-sysinstall/backend-query/setup-ssh-keys.sh
+/usr/sbin/pc-sysinstall/backend-query/sys-mem.sh
+/usr/sbin/pc-sysinstall/backend-query/test-live.sh
+/usr/sbin/pc-sysinstall/backend-query/test-netup.sh
+/usr/sbin/pc-sysinstall/backend-query/update-part-list.sh
+/usr/sbin/pc-sysinstall/backend-query/xkeyboard-layouts.sh
+/usr/sbin/pc-sysinstall/backend-query/xkeyboard-models.sh
+/usr/sbin/pc-sysinstall/backend-query/xkeyboard-variants.sh
+/usr/sbin/pc-sysinstall/backend/Makefile
+/usr/sbin/pc-sysinstall/backend/functions-bsdlabel.sh
+/usr/sbin/pc-sysinstall/backend/functions-cleanup.sh
+/usr/sbin/pc-sysinstall/backend/functions-disk.sh
+/usr/sbin/pc-sysinstall/backend/functions-extractimage.sh
+/usr/sbin/pc-sysinstall/backend/functions-ftp.sh
+/usr/sbin/pc-sysinstall/backend/functions-installcomponents.sh
+/usr/sbin/pc-sysinstall/backend/functions-installpackages.sh
+/usr/sbin/pc-sysinstall/backend/functions-localize.sh
+/usr/sbin/pc-sysinstall/backend/functions-mountdisk.sh
+/usr/sbin/pc-sysinstall/backend/functions-mountoptical.sh
+/usr/sbin/pc-sysinstall/backend/functions-networking.sh
+/usr/sbin/pc-sysinstall/backend/functions-newfs.sh
+/usr/sbin/pc-sysinstall/backend/functions-packages.sh
+/usr/sbin/pc-sysinstall/backend/functions-parse.sh
+/usr/sbin/pc-sysinstall/backend/functions-runcommands.sh
+/usr/sbin/pc-sysinstall/backend/functions-unmount.sh
+/usr/sbin/pc-sysinstall/backend/functions-upgrade.sh
+/usr/sbin/pc-sysinstall/backend/functions-users.sh
+/usr/sbin/pc-sysinstall/backend/functions.sh
+/usr/sbin/pc-sysinstall/backend/installimage.sh
+/usr/sbin/pc-sysinstall/backend/parseconfig.sh
+/usr/sbin/pc-sysinstall/backend/startautoinstall.sh
+/usr/sbin/pc-sysinstall/conf/Makefile
+/usr/sbin/pc-sysinstall/conf/avail-langs
+/usr/sbin/pc-sysinstall/conf/exclude-from-upgrade
+/usr/sbin/pc-sysinstall/conf/licenses/bsd-en.txt
+/usr/sbin/pc-sysinstall/conf/licenses/intel-en.txt
+/usr/sbin/pc-sysinstall/conf/licenses/nvidia-en.txt
+/usr/sbin/pc-sysinstall/conf/pc-sysinstall.conf
+/usr/sbin/pc-sysinstall/doc/Makefile
+/usr/sbin/pc-sysinstall/doc/help-disk-list
+/usr/sbin/pc-sysinstall/doc/help-disk-size
+/usr/sbin/pc-sysinstall/doc/help-index
+/usr/sbin/pc-sysinstall/doc/help-start-autoinstall
+/usr/sbin/pc-sysinstall/examples/Makefile
+/usr/sbin/pc-sysinstall/examples/README
+/usr/sbin/pc-sysinstall/examples/pc-autoinstall.conf
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.fbsd-netinstall
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.geli
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.gmirror
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.netinstall
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.restore
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.rsync
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.upgrade
+/usr/sbin/pc-sysinstall/examples/pcinstall.cfg.zfs
+/usr/sbin/pc-sysinstall/examples/pfSense.cfg
+/usr/sbin/pc-sysinstall/examples/pfSense.cfg.zfs
+/usr/sbin/pc-sysinstall/pc-sysinstall/Makefile
+/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.8
+/usr/sbin/pc-sysinstall/pc-sysinstall/pc-sysinstall.sh
+/usr/sbin/pkg_add
+/usr/sbin/pkg_check
+/usr/sbin/pkg_create
+/usr/sbin/pkg_delete
+/usr/sbin/pkg_info
+/usr/sbin/pkg_sign
+/usr/sbin/pkg_updating
+/usr/sbin/pkg_version
+/usr/sbin/pppd
+/usr/sbin/pppstats
+/usr/sbin/praudit
+/usr/sbin/sliplogin
+/usr/sbin/unbound
+/usr/sbin/unbound-anchor
+/usr/sbin/unbound-checkconf
+/usr/sbin/unbound-control
+/usr/sbin/unbound-control-setup
+/usr/sbin/usbdevs
+/usr/sbin/wicontrol
+/usr/share/man
+/usr/share/misc/gprof.callg
+/usr/share/misc/gprof.flat
+/usr/share/nls/C/ee.cat
+/usr/share/nls/POSIX/ee.cat
+/usr/share/nls/en_US.US-ASCII/ee.cat
+/usr/share/syscons
+/usr/share/zoneinfo/GMT
+/var/db/dhclient.leases.sis1
+/var/db/rrd/71
+/var/db/rrd/index.html
+/var/dhcpd/lib/libc.so.6
+/var/etc/pppoe-vpn
+/var/mail/_relayd
+/var/mail/unbound
diff --git a/src/etc/phpshellsessions/changepassword b/src/etc/phpshellsessions/changepassword
new file mode 100644
index 0000000..6243fb8
--- /dev/null
+++ b/src/etc/phpshellsessions/changepassword
@@ -0,0 +1,79 @@
+require_once("config.inc");
+require("auth.inc");
+require_once("functions.inc");
+
+global $g, $config, $argv, $userindex;
+$userindex = index_users();
+
+$args = array_slice($argv, 3);
+
+$password = "";
+$confpassword = "";
+$username = "";
+
+$fp = fopen('php://stdin', 'r');
+
+// If the first parameter is empty, ask for username
+if (empty($args[0])) {
+ echo gettext("Enter username: ");
+ $username = fgets($fp);
+} else {
+ $username = $args[0];
+}
+$username = trim($username);
+
+// If the user does not exist, bail
+$user =& getUserEntry($username);
+if ($user == NULL) {
+ printf(gettext("User '%s' does not exist.\n"), $username);
+ exit(-1);
+} else {
+ printf(gettext("Changing password for '%s'.\n"), $username);
+}
+
+// If the user does exist, prompt for password
+while (empty($password)) {
+ echo gettext("New Password") . ": ";
+ exec('/bin/stty -echo');
+ $password = trim(fgets($fp));
+ exec('/bin/stty echo');
+ echo "\n";
+}
+
+// Confirm password
+while (empty($confpassword)) {
+ echo gettext("Confirm New Password") . ": ";
+ exec('/bin/stty -echo');
+ $confpassword = trim(fgets($fp));
+ exec('/bin/stty echo');
+ echo "\n";
+}
+
+// Check if user is disabled
+if (is_account_disabled($username)) {
+ echo gettext("Account is disabled, would you like to re-enable? [y|n]") . ": ";
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+ unset($user['disabled']);
+ }
+}
+// Check if user is expired
+if (is_account_expired($username)) {
+ echo gettext("Account is expired, would you like to clear the expiration date? [y|n]") . ": ";
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+ unset($user['expires']);
+ }
+}
+
+fclose($fp);
+
+// Compare password and confirm
+if ($password == $confpassword) {
+ //Reset password
+ local_user_set_password($user, $password);
+ local_user_set($user);
+ write_config(sprintf(gettext("password changed for user '%s' from console."), $username));
+ exit(0);
+} else {
+ echo gettext("New and Confirm passwords did not match.") . "\n";
+ exit(-1);
+} \ No newline at end of file
diff --git a/src/etc/phpshellsessions/disablecarp b/src/etc/phpshellsessions/disablecarp
new file mode 100644
index 0000000..1673269
--- /dev/null
+++ b/src/etc/phpshellsessions/disablecarp
@@ -0,0 +1,17 @@
+! echo "Disabling CARP..."
+require_once("config.inc");
+require_once("interfaces.inc");
+require_once("util.inc");
+
+set_single_sysctl("net.inet.carp.allow", "0");
+if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ switch ($vip['mode']) {
+ case "carp":
+ interface_vip_bring_down($vip);
+ sleep(1);
+ break;
+ }
+ }
+}
diff --git a/src/etc/phpshellsessions/disabledhcpd b/src/etc/phpshellsessions/disabledhcpd
new file mode 100644
index 0000000..4dc029c
--- /dev/null
+++ b/src/etc/phpshellsessions/disabledhcpd
@@ -0,0 +1,13 @@
+global $config;
+
+$config = parse_config(true);
+
+unset($config['dhcpd']);
+
+echo "Disabling DHCP Server on all interfaces...";
+
+write_config("pfSsh.php disabled dhcp on all interfaces");
+
+services_dhcpd_configure();
+
+echo "done.\n"; \ No newline at end of file
diff --git a/src/etc/phpshellsessions/disablereferercheck b/src/etc/phpshellsessions/disablereferercheck
new file mode 100644
index 0000000..97d444a
--- /dev/null
+++ b/src/etc/phpshellsessions/disablereferercheck
@@ -0,0 +1,11 @@
+global $config;
+
+$config = parse_config(true);
+
+$config['system']['webgui']['nohttpreferercheck'] = true;
+
+echo "Disabling HTTP referer check...";
+
+write_config("PHP shell disabled HTTP referer check");
+
+echo "done.\n";
diff --git a/src/etc/phpshellsessions/enableallowallwan b/src/etc/phpshellsessions/enableallowallwan
new file mode 100644
index 0000000..5ce4f0f
--- /dev/null
+++ b/src/etc/phpshellsessions/enableallowallwan
@@ -0,0 +1,36 @@
+global $config;
+require_once("filter.inc");
+require("shaper.inc");
+$config = parse_config(true);
+echo "Adding allow all rule...\n";
+$filterent = array();
+$filterent["type"] = "pass";
+$filterent["interface"] = "wan";
+$filterent["source"]["any"] = "";
+$filterent["destination"]["any"] = "";
+$filterent["statetype"] = "keep state";
+$filterent["os"] = "";
+$filterent["descr"] = "Allow all ipv4 via pfSsh.php";
+$config["filter"]["rule"][] = $filterent;
+$filterent = array();
+$filterent["type"] = "pass";
+$filterent["ipprotocol"] = "inet6";
+$filterent["interface"] = "wan";
+$filterent["source"]["any"] = "";
+$filterent["destination"]["any"] = "";
+$filterent["statetype"] = "keep state";
+$filterent["os"] = "";
+$filterent["descr"] = "Allow all ipv6 via pfSsh.php";
+$config["filter"]["rule"][] = $filterent;
+echo "Turning off block private networks (if on)...\n";
+unset($config["interfaces"]["wan"]["blockpriv"]);
+echo "Turning off block bogon networks (if on)...\n";
+unset($config["interfaces"]["wan"]["blockbogons"]);
+unlink_if_exists("/tmp/config.cache");
+write_config("pfSsh.php added allow all wan rule");
+unlink_if_exists("/tmp/config.cache");
+unset($config['interfaces']['wan']['blockbogons']);
+$config = parse_config(true);
+echo "Reloading the filter configuration...";
+filter_configure_sync();
+echo "\n\n"; \ No newline at end of file
diff --git a/src/etc/phpshellsessions/enablecarp b/src/etc/phpshellsessions/enablecarp
new file mode 100644
index 0000000..276f29a
--- /dev/null
+++ b/src/etc/phpshellsessions/enablecarp
@@ -0,0 +1,23 @@
+! echo "Enabling CARP..."
+require_once("config.inc");
+require_once("interfaces.inc");
+require_once("util.inc");
+
+if (is_array($config['virtualip']['vip'])) {
+ $viparr = &$config['virtualip']['vip'];
+ foreach ($viparr as $vip) {
+ switch ($vip['mode']) {
+ case "carp":
+ interface_carp_configure($vip);
+ sleep(1);
+ break;
+ case "ipalias":
+ if (strpos($vip['interface'], '_vip')) {
+ interface_ipalias_configure($vip);
+ }
+ break;
+ }
+ }
+}
+interfaces_sync_setup();
+set_single_sysctl("net.inet.carp.allow", "1");
diff --git a/src/etc/phpshellsessions/enablesshd b/src/etc/phpshellsessions/enablesshd
new file mode 100644
index 0000000..0dc76de
--- /dev/null
+++ b/src/etc/phpshellsessions/enablesshd
@@ -0,0 +1,12 @@
+global $config;
+echo "Starting enablesshd...";
+require("config.inc");
+echo ".";
+$config = parse_config(true);
+echo ".";
+$config['system']['enablesshd'] = true;
+echo ".";
+write_config("pfSsh.php enabled sshd");
+echo "\nEnabling SSHD, please wait...";
+send_event("service reload sshd");
+echo "\n\n";
diff --git a/src/etc/phpshellsessions/externalconfiglocator b/src/etc/phpshellsessions/externalconfiglocator
new file mode 100644
index 0000000..84534b3
--- /dev/null
+++ b/src/etc/phpshellsessions/externalconfiglocator
@@ -0,0 +1,3 @@
+
+include("/etc/ecl.php");
+
diff --git a/src/etc/phpshellsessions/generateguicert b/src/etc/phpshellsessions/generateguicert
new file mode 100644
index 0000000..925ab60
--- /dev/null
+++ b/src/etc/phpshellsessions/generateguicert
@@ -0,0 +1,8 @@
+require_once("system.inc");
+
+echo gettext("Generating a new self-signed SSL certificate for the GUI...");
+$cert = system_webgui_create_certificate();
+echo gettext("Done.\n");
+echo gettext("Restarting webConfigurator...");
+send_event("service restart webgui");
+echo gettext("Done.\n"); \ No newline at end of file
diff --git a/src/etc/phpshellsessions/gitsync b/src/etc/phpshellsessions/gitsync
new file mode 100644
index 0000000..aced804
--- /dev/null
+++ b/src/etc/phpshellsessions/gitsync
@@ -0,0 +1,434 @@
+/* cvs_sync
+ * Written by Scott Ullrich
+ * (C)2005-2007 Scott Ullrich
+ * (C)2010-2012 Erik Fonnesbeck
+ * Part of the pfSense project pfSsh.php subsystem
+ */
+
+require_once("globals.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("rrd.inc");
+require_once("pfsense-utils.inc");
+
+$GIT_PKG = "git"; // Either "git" or the full package URL
+$GIT_BIN= "/usr/local/bin/git";
+$GIT_REPO = "git://github.com/pfsense/pfsense.git";
+$DEFAULT_BRANCH = "master";
+$CODIR = "/root/pfsense";
+$GITSYNC_MERGE = "/root/.gitsync_merge";
+
+/* NOTE: Set branches here */
+$branches = array(
+ "master" => "2.2 development branch",
+ "RELENG_2_2" => "2.2.* release branch",
+ "RELENG_2_1" => "2.1.* release branch",
+ "RELENG_2_0" => "2.0.* release branch",
+ "RELENG_1_2" => "1.2.* release branch",
+ "build_commit" => "The commit originally used to build the image"
+);
+
+global $g;
+global $argv;
+global $command_split;
+
+if (is_array($command_split)) {
+ $temp_args = array_slice($command_split, 2);
+} else {
+ $temp_args = array_slice($argv, 3);
+}
+
+$valid_args = array(
+ "--minimal" => "\tPerform a minimal copy of only the updated files.\n" .
+ "\tNot recommended if the system has files modified by any method other\n" .
+ "\tthan gitsync.\n",
+ "--help" => "\tDisplay this help list.\n"
+ );
+$args = array();
+$arg_count = 0;
+while (!empty($temp_args)) {
+ $arg = array_shift($temp_args);
+ if ($arg[0] == '-') {
+ switch ($arg) {
+ case "--help":
+ echo "Usage: playback gitsync [options] [[repository] <branch>]\nOptions:\n";
+ foreach($valid_args as $arg_name => $arg_desc) {
+ echo $arg_name . "\n" . $arg_desc;
+ }
+ exit;
+ case "--upgrading":
+ // Disables all interactive functions and neither PHP
+ // nor the web GUI will be killed or restarted.
+ $upgrading = true;
+ case (isset($valid_args[$arg])):
+ $args[$arg] = true;
+ break;
+ default:
+ echo "Invalid option: {$arg}\nUse --help for usage information.\n";
+ exit;
+ }
+ } else {
+ $args[$arg_count++] = $arg;
+ }
+}
+
+unlink_if_exists("/tmp/config.cache");
+conf_mount_rw();
+
+if (!file_exists($GIT_BIN)) {
+ require_once("pkg-utils.inc");
+
+ echo "Cannot find git, installing...\n";
+ if (!pkg_call('install -y -q git-lite')) {
+ echo "\nERROR: Unable to install git pkg.\n";
+ return;
+ }
+}
+
+# Remove mainline if exists (older)
+if (is_dir("/root/pfsense/mainline")) {
+ exec("rm -rf /root/pfsense/mainline");
+}
+
+# Remove RELENG_1_2 if exists (older)
+if (is_dir("/root/pfsense/RELENG_1_2")) {
+ exec("rm -rf /root/pfsense/RELENG_1_2");
+}
+
+# Remove HEAD if exists (older)
+if (is_dir("/root/pfsense/HEAD")) {
+ exec("rm -rf /root/pfsense/HEAD");
+}
+
+if (file_exists("/root/cvssync_backup.tgz")) {
+ $backup_date = `ls -lah /root/cvssync_backup.tgz | awk '{ print $6,$7,$8 }'`;
+ $tmp = array("RESTORE" => "Restores prior CVSSync backup data performed at {$backup_date}");
+ $branches = array_merge($branches, $tmp);
+}
+
+if (is_dir("$CODIR/pfSenseGITREPO/pfSenseGITREPO")) {
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} config remote.origin.url", $output_str, $ret);
+ if (is_array($output_str) && !empty($output_str[0])) {
+ $GIT_REPO = $output_str[0];
+ }
+ unset($output_str);
+}
+
+if (!$args[0] && !$upgrading) {
+ echo "\nCurrent repository is $GIT_REPO\n";
+ echo "\nPlease select which branch you would like to sync against:\n\n";
+ foreach ($branches as $branchname => $branchdesc) {
+ echo "{$branchname} \t {$branchdesc}\n";
+ }
+ echo "\nOr alternatively you may enter a custom RCS branch URL (Git or HTTP).\n\n";
+ $branch = readline("> ");
+ echo "\n";
+} else {
+ $branch = $args[0];
+}
+
+if ($args[1] == "NOBACKUP") {
+ $nobackup = true;
+} else {
+ $nobackup = false;
+}
+
+// If the repository has been fetched before, build a list of its branches.
+if (is_dir("$CODIR/pfSenseGITREPO/pfSenseGITREPO")) {
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} branch -r", $branch_list, $ret);
+ if ($ret == 0 && is_array($branch_list)) {
+ foreach ($branch_list as $branch_item) {
+ $branch_item = substr(strrchr($branch_item, "/"), 1);
+ if (!isset($branches[$branch_item])) {
+ $branches[$branch_item] = " ";
+ }
+ }
+ }
+}
+
+$found = false;
+foreach ($branches as $branchname => $branchdesc) {
+ if ($branchname == $branch) {
+ $found = true;
+ }
+}
+if (!$found) {
+ if (isURL($branch) && !$upgrading) {
+ if ($args[1]) {
+ $GIT_REPO = $branch;
+ $branch = $args[1];
+ $found = true;
+ } else {
+ echo "\n";
+ echo "NOTE: $branch was not found.\n\n";
+ $command = readline("Is this a custom GIT URL? [y]? ");
+ if (strtolower($command) == "y" or $command == "") {
+ $GIT_REPO = $branch;
+ $command = readline("Checkout which branch [${DEFAULT_BRANCH}]? ");
+ if ($command == "") {
+ $branch = $DEFAULT_BRANCH;
+ }
+ if ($command) {
+ $branch = $command;
+ }
+ $found = true;
+ }
+ }
+ }
+ if (!$found) {
+ echo "\nNo valid branch found. Exiting.\n\n";
+ conf_mount_ro();
+ exit;
+ }
+}
+
+$merge_repos = array();
+if (file_exists($GITSYNC_MERGE)) {
+ $gitsync_merges = file($GITSYNC_MERGE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!empty($gitsync_merges) && is_array($gitsync_merges)) {
+ echo "\n===> Automatic merge list read from ${GITSYNC_MERGE}\n";
+ foreach ($gitsync_merges as $merge_line_num => $merge_line) {
+ $merge_comments = explode("#", trim($merge_line));
+ if (empty($merge_comments[0])) {
+ continue;
+ }
+
+ $merge_line = explode(" ", trim($merge_comments[0]));
+ if (count($merge_line) != 2 || empty($merge_line[0]) || empty($merge_line[1])) {
+ echo "\nLine " . ($merge_line_num + 1) . " does not have the correct parameter count or has improper spacing.\n";
+ echo "Expected parameters: repository_url branch\n";
+ echo "Line read: " . implode(" ", $merge_line) . "\n\n";
+ echo "Aborting automatic merge.\n\n";
+ $merge_repos = array();
+ break;
+ }
+ $merge_repos[] = array('repo' => $merge_line[0], 'branch' => $merge_line[1]);
+ }
+ }
+}
+if (!$args[0] && !$upgrading) {
+ do {
+ echo "\nAdd a custom RCS branch URL (Git or HTTP) to merge in or press enter if done.\n\n";
+ $merge_repo = readline("> ");
+ if (!empty($merge_repo)) {
+ $merge_branch = readline("Merge which branch [${DEFAULT_BRANCH}]? ");
+ if ($merge_branch == "") {
+ $merge_repos[] = array('repo' => $merge_repo, 'branch' => $DEFAULT_BRANCH);
+ } else if ($merge_branch) {
+ $merge_repos[] = array('repo' => $merge_repo, 'branch' => $merge_branch);
+ }
+ }
+ } while (!empty($merge_repo));
+}
+
+if ($branch == "RESTORE" && $g['platform'] == "pfSense") {
+ if (!file_exists("/root/cvssync_backup.tgz")) {
+ echo "Sorry, we could not find a previous CVSSync backup file.\n";
+ conf_mount_ro();
+ exit();
+ }
+ echo "===> Restoring previous CVSSync backup... Please wait...\n";
+ exec("tar Uxpf /root/cvssync_backup.tgz -C /");
+ post_cvssync_commands();
+ conf_mount_ro();
+ exit();
+} else {
+ $nobackup = true; // do not backup embedded, livecd
+}
+
+if ($nobackup == false) {
+ echo "===> Backing up current pfSense information...\n";
+ echo "===> Please wait... ";
+ exec("tar czPf /root/cvssync_backup.tgz --exclude /root --exclude /dev --exclude /tmp --exclude /var/run --exclude /var/empty /");
+ $size = filesize("/root/cvssync_backup.tgz");
+ echo "{$size} bytes.\n\n";
+ sleep(5);
+}
+
+echo "===> Checking out $branch\n";
+
+// Git commands for resetting to the specified branch
+if ($branch == "build_commit") {
+ $git_cmd = array(
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} branch " . escapeshellarg($branch) . " 2>/dev/null",
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} checkout -f " . escapeshellarg($branch) . " 2>/dev/null",
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} reset --hard " . escapeshellarg(trim(file_get_contents("/etc/version.lastcommit")))
+ );
+} else {
+ $git_cmd = array(
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} branch " . escapeshellarg($branch) . " " . escapeshellarg("origin/{$branch}") . " 2>/dev/null",
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} checkout -f " . escapeshellarg($branch) . " 2>/dev/null",
+ "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} reset --hard " . escapeshellarg("origin/{$branch}")
+ );
+}
+
+// Git 'er done!
+if (is_dir("$CODIR/pfSenseGITREPO/pfSenseGITREPO")) {
+ echo "===> Fetching updates...\n";
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} config remote.origin.url " . escapeshellarg($GIT_REPO));
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} fetch");
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} clean -f -f -x -d");
+ run_cmds($git_cmd);
+} else {
+ exec("mkdir -p $CODIR/pfSenseGITREPO");
+ echo "Executing cd $CODIR/pfSenseGITREPO && {$GIT_BIN} clone $GIT_REPO pfSenseGITREPO\n";
+ exec("cd $CODIR/pfSenseGITREPO && {$GIT_BIN} clone " . escapeshellarg($GIT_REPO) . " pfSenseGITREPO");
+ if (is_dir("$CODIR/pfSenseGITREPO/pfSense")) {
+ exec("mv $CODIR/pfSenseGITREPO/pfSense $CODIR/pfSenseGITREPO/pfSenseGITREPO");
+ }
+ if (is_dir("$CODIR/pfSenseGITREPO/mainline")) {
+ exec("mv $CODIR/pfSenseGITREPO/mainline $CODIR/pfSenseGITREPO/pfSenseGITREPO");
+ }
+ run_cmds($git_cmd);
+}
+
+foreach ($merge_repos as $merge_repo) {
+ echo "===> Merging branch {$merge_repo['branch']} from {$merge_repo['repo']}\n";
+ exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} pull " . escapeshellarg($merge_repo['repo']) . " " . escapeshellarg($merge_repo['branch']), $output_str, $ret);
+ unset($output_str);
+ if ($ret <> 0) {
+ echo "\nMerge failed. Aborting sync.\n\n";
+ run_cmds($git_cmd);
+ conf_mount_ro();
+ exit;
+ }
+}
+
+if (isset($args["--minimal"])) {
+ if (file_exists("/etc/version.gitsync")) {
+ $old_revision = trim(file_get_contents("/etc/version.gitsync"));
+ } else if (file_exists("/etc/version.lastcommit")) {
+ $old_revision = trim(file_get_contents("/etc/version.lastcommit"));
+ }
+ $files_to_copy = strtr(shell_exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} diff --name-only " . escapeshellarg($old_revision)), "\n", " ");
+} else {
+ $files_to_copy = '--exclude .git .';
+}
+
+// Save new commit ID for later minimal file copies
+exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} rev-parse -q --verify HEAD > /etc/version.gitsync");
+
+exec("mkdir -p /tmp/lighttpd/cache/compress/");
+
+// Nuke CVS and pfSense tarballs
+exec("cd ${CODIR}/pfSenseGITREPO/pfSenseGITREPO && find . -name CVS -exec rm -rf {} \; 2>/dev/null");
+exec("cd ${CODIR}/pfSenseGITREPO/pfSenseGITREPO && find . -name pfSense.tgz -exec rm {} \; 2>/dev/null");
+
+// Remove files that we do not want to overwrite the system with
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/crontab 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/master.passwd 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/passwd 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/fstab 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/ttys 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/group 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/fstab 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/platform 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/boot/device.hints 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/boot/loader.conf 2>/dev/null");
+exec("rm ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/boot/loader.rc 2>/dev/null");
+exec("rm -rf ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/conf*");
+exec("rm -rf ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/cf 2>/dev/null");
+exec("rm -rf ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/root/.shrc");
+exec("rm -rf ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/root/.tcshrc");
+exec("rm -f ${CODIR}/pfSenseGITREPO/pfSenseGITREPO/etc/syslog.conf 2>/dev/null");
+
+echo "===> Installing new files...\n";
+
+if ($g['platform'] == "pfSense") {
+ $command = "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO ; tar -cpf - {$files_to_copy} | (cd / ; tar -Uxpf -)";
+} else {
+ $command = "cd $CODIR/pfSenseGITREPO/pfSenseGITREPO ; tar -cpf - {$files_to_copy} | (cd / ; tar -xpf -) 2>/dev/null";
+}
+
+if (!empty($files_to_copy)) {
+ exec($command);
+} else {
+ echo "Already up-to-date.\n";
+ $upgrading = true;
+}
+
+// Reset the repository to restore the deleted files
+exec("cd $CODIR/pfSenseGITREPO/pfSenseGITREPO && {$GIT_BIN} reset --hard >/dev/null 2>/dev/null");
+
+// Remove obsolete files
+$files_to_remove = file("/etc/pfSense.obsoletedfiles");
+foreach ($files_to_remove as $file_to_remove) {
+ if (file_exists($file_to_remove)) {
+ exec("/bin/rm -f $file_to_remove");
+ }
+}
+
+if (!$upgrading) {
+ post_cvssync_commands();
+}
+
+echo "===> Checkout complete.\n";
+echo "\n";
+if (!$upgrading) {
+ echo "Your system is now sync'd and PHP and Lighty will be restarted in 5 seconds.\n\n";
+} else {
+ echo "Your system is now sync'd.\n\n";
+}
+
+function post_cvssync_commands() {
+ echo "===> Removing FAST-CGI temporary files...\n";
+ exec("find /tmp -name \"php-fastcgi.socket*\" -exec rm -rf {} \;");
+ exec("find /tmp -name \"*.tmp\" -exec rm -rf {} \;");
+
+ exec("rm -rf /tmp/xcache/* 2>/dev/null");
+
+ echo "===> Upgrading configuration (if needed)...\n";
+ convert_config();
+
+ echo "===> Configuring filter...";
+ exec("/etc/rc.filter_configure_sync");
+ exec("pfctl -f /tmp/rules.debug");
+ echo "\n";
+
+ if (file_exists("/etc/rc.php_ini_setup")) {
+ echo "===> Running /etc/rc.php_ini_setup...";
+ exec("/etc/rc.php_ini_setup");
+ echo "\n";
+ }
+
+ /* lock down console if necessary */
+ echo "===> Locking down the console if needed...\n";
+ reload_ttys();
+
+ echo "===> Signaling PHP and Lighty restart...";
+ $fd = fopen("/tmp/restart_lighty", "w");
+ fwrite($fd, "#!/bin/sh\n");
+ fwrite($fd, "sleep 5\n");
+ fwrite($fd, "/usr/local/sbin/pfSctl -c 'service restart webgui'\n");
+ if (file_exists("/var/etc/lighty-CaptivePortal.conf")) {
+ fwrite($fd, "/usr/local/sbin/lighttpd -f /var/etc/lighty-CaptivePortal.conf\n");
+ }
+ fclose($fd);
+ mwexec_bg("sh /tmp/restart_lighty");
+ echo "\n";
+
+}
+
+function isUrl($url = "") {
+ if ($url) {
+ if (strstr($url, "rcs.pfsense.org") or
+ strstr($url, "mainline") or
+ strstr($url, ".git") or
+ strstr($url, "git://")) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function run_cmds($cmds) {
+ global $debug;
+ foreach ($cmds as $cmd) {
+ if ($debug) {
+ echo "Running $cmd";
+ }
+ exec($cmd);
+ }
+}
+
+conf_mount_ro();
diff --git a/src/etc/phpshellsessions/installpkg b/src/etc/phpshellsessions/installpkg
new file mode 100644
index 0000000..1ac71bf
--- /dev/null
+++ b/src/etc/phpshellsessions/installpkg
@@ -0,0 +1,36 @@
+require_once("config.inc");
+require_once("util.inc");
+require_once("pkg-utils.inc");
+
+global $g, $config, $argv, $command_split;
+
+if (is_array($command_split)) {
+ $args = array_slice($command_split, 1);
+} else {
+ $args = array_slice($argv, 2);
+}
+
+$pkg_name = $args[0];
+
+echo "Installing package \"{$pkg_name}\"...\n";
+
+echo "Trying to fetch package info...";
+$pkg_info = get_pkg_info();
+if ($pkg_info) {
+ echo " Done.\n";
+} else {
+ echo "\n" . gettext(' >>> Unable to get pkg info.') . "\n";
+ return;
+}
+
+$static_output = "";
+$pkg_interface = "console";
+
+if (empty($pkg_info[$pkg_name])) {
+ echo "\nPackage not found.\n";
+ return;
+}
+
+install_package($pkg_name);
+
+echo "\nDone.\n";
diff --git a/src/etc/phpshellsessions/listpkg b/src/etc/phpshellsessions/listpkg
new file mode 100644
index 0000000..ed2c793
--- /dev/null
+++ b/src/etc/phpshellsessions/listpkg
@@ -0,0 +1,16 @@
+require_once("config.inc");
+require_once("util.inc");
+
+global $g, $config;
+
+echo "Installed packages:\n";
+
+foreach ($config['installedpackages']['package'] as $package) {
+ $name = str_pad("{$package['name']}-{$package['version']}", 30);
+ $descr = $package['descr'];
+ $line = "{$name} {$descr}";
+ if (strlen($line) > 80) {
+ $line = substr($line, 0, 77) . "...";
+ }
+ echo "{$line}\n";
+}
diff --git a/src/etc/phpshellsessions/removepkgconfig b/src/etc/phpshellsessions/removepkgconfig
new file mode 100644
index 0000000..ea365bf
--- /dev/null
+++ b/src/etc/phpshellsessions/removepkgconfig
@@ -0,0 +1,8 @@
+global $config;
+$config = parse_config(true);
+unset($config['installedpackages']);
+echo "Clearing package configuration information...\n";
+write_config("pfSsh.php cleared package configuration data.");
+$config = parse_config(true);
+echo "Removing startup files from /usr/local/etc/rc.d/...\n";
+exec("rm /usr/local/etc/rc.d/*");
diff --git a/src/etc/phpshellsessions/removeshaper b/src/etc/phpshellsessions/removeshaper
new file mode 100644
index 0000000..298e618
--- /dev/null
+++ b/src/etc/phpshellsessions/removeshaper
@@ -0,0 +1,25 @@
+require("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("rrd.inc");
+
+/* Much of this borrowed from firewall_shaper.php */
+
+echo gettext("Removing shaper settings...\n");
+
+unset($config['shaper']['queue']);
+unset($queue);
+unset($altq);
+
+foreach ($config['filter']['rule'] as $key => $rule) {
+ if (isset($rule['wizard']) && $rule['wizard'] == "yes") {
+ unset($config['filter']['rule'][$key]);
+ }
+}
+if (write_config()) {
+ echo gettext("Shaper Successfully Removed.\n");
+} else {
+ echo gettext("Unable to write config.xml (Access Denied?)\n");
+}
+filter_configure(); \ No newline at end of file
diff --git a/src/etc/phpshellsessions/restartdhcpd b/src/etc/phpshellsessions/restartdhcpd
new file mode 100644
index 0000000..e24c842
--- /dev/null
+++ b/src/etc/phpshellsessions/restartdhcpd
@@ -0,0 +1,4 @@
+! echo "Killing dhcp server..."
+! killall dhcpd
+! echo "Restarting dhcp server..."
+services_dhcpd_configure();
diff --git a/src/etc/phpshellsessions/restartipsec b/src/etc/phpshellsessions/restartipsec
new file mode 100644
index 0000000..ebbe9b3
--- /dev/null
+++ b/src/etc/phpshellsessions/restartipsec
@@ -0,0 +1,7 @@
+! echo "Restarting ipsec..."
+require_once("config.inc");
+require_once("filter.inc");
+require_once("auth.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+vpn_ipsec_configure(true);
diff --git a/src/etc/phpshellsessions/svc b/src/etc/phpshellsessions/svc
new file mode 100644
index 0000000..ee1ab40
--- /dev/null
+++ b/src/etc/phpshellsessions/svc
@@ -0,0 +1,99 @@
+require_once("config.inc");
+require_once("util.inc");
+require_once("service-utils.inc");
+
+function usage() {
+ echo "Usage: playback svc <action> <service name> [service-specific options]\n\n";
+ echo "Examples:\n";
+ echo "playback svc stop dhcpd\n";
+ echo "playback svc restart openvpn client 2\n";
+ echo "playback svc stop captiveportal zone1\n";
+ echo "\n";
+}
+
+global $g, $config, $argv, $command_split;
+
+if (is_array($command_split)) {
+ $args = array_slice($command_split, 2);
+} else {
+ $args = array_slice($argv, 3);
+}
+
+if (empty($args[0])) {
+ usage();
+}
+
+$extras = array();
+
+// start, stop, restart
+$action = $args[0];
+
+// dhcpd, openvpn, etc.
+$svc_name = $args[1];
+
+// Handle servive-specific options.
+switch ($svc_name) {
+ case "openvpn":
+ if (in_array($args[2], array("server", "client"))) {
+ $extras['vpnmode'] = $args[2];
+ } else {
+ echo "Invalid OpenVPN mode (server, client)\n";
+ return;
+ }
+ if (is_numeric($args[3])) {
+ $extras['id'] = $args[3];
+ } else {
+ echo "Invalid OpenVPN ID, must be numeric\n";
+ return;
+ }
+ $vpnsvc = find_service_by_openvpn_vpnid($extras['id']);
+ if (empty($vpnsvc)) {
+ echo "No OpenVPN client or server found with that ID.\n";
+ return;
+ }
+ break;
+ case "captiveportal":
+ if (is_validaliasname($args[2])) {
+ $extras['zone'] = $args[2];
+ } else {
+ echo "Invalid Captive Portal Zone.\n";
+ return;
+ }
+ $cpzone = find_service_by_cp_zone($extras['zone']);
+ if (empty($cpzone)) {
+ echo "No Captive Portal Zone found with that name.\n";
+ return;
+ }
+ break;
+}
+
+switch ($action) {
+ case "restart":
+ echo "Attempting to issue {$action} to {$svc_name} service...\n";
+ $savemsg = service_control_restart($svc_name, $extras);
+ break;
+ case "start":
+ echo "Attempting to issue {$action} to {$svc_name} service...\n";
+ $savemsg = service_control_start($svc_name, $extras);
+ break;
+ case "stop":
+ echo "Attempting to issue {$action} to {$svc_name} service...\n";
+ $savemsg = service_control_stop($svc_name, $extras);
+ break;
+ case "status":
+ switch ($svc_name) {
+ case "openvpn":
+ $service = $vpnsvc;
+ break;
+ case "captiveportal":
+ $service = $cpzone;
+ break;
+ default:
+ $service = find_service_by_name($svc_name);
+ break;
+ }
+ $savemsg = get_service_status($service) ? "Service {$svc_name} is running." : "Service {$svc_name} is stopped.";
+ break;
+}
+
+echo "\n{$savemsg}\n";
diff --git a/src/etc/phpshellsessions/uninstallpkg b/src/etc/phpshellsessions/uninstallpkg
new file mode 100644
index 0000000..9030e56
--- /dev/null
+++ b/src/etc/phpshellsessions/uninstallpkg
@@ -0,0 +1,34 @@
+require_once("config.inc");
+require_once("util.inc");
+require_once("pkg-utils.inc");
+
+global $g, $config, $argv, $command_split;
+
+if (is_array($command_split)) {
+ $args = array_slice($command_split, 1);
+} else {
+ $args = array_slice($argv, 2);
+}
+
+$pkg_name = $args[0];
+$pkg_info = array();
+
+echo "Removing package \"{$pkg_name}\"...\n";
+
+foreach ($config['installedpackages']['package'] as $package) {
+ if ($pkg_name == $package['name']) {
+ $pkg_info = $package;
+ }
+}
+
+$static_output = "";
+$pkg_interface = "console";
+
+if (empty($pkg_info)) {
+ echo "\nPackage not installed.\n";
+ return;
+}
+
+uninstall_package($pkg_name);
+
+echo "\nDone.\n";
diff --git a/src/etc/platform b/src/etc/platform
new file mode 100644
index 0000000..8443722
--- /dev/null
+++ b/src/etc/platform
@@ -0,0 +1 @@
+pfSense \ No newline at end of file
diff --git a/src/etc/printcap b/src/etc/printcap
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/etc/printcap
diff --git a/src/etc/protocols b/src/etc/protocols
new file mode 100644
index 0000000..763cbcd
--- /dev/null
+++ b/src/etc/protocols
@@ -0,0 +1,158 @@
+#
+# Internet protocols
+#
+# $FreeBSD: stable/10/etc/protocols 250453 2013-05-10 13:57:44Z eadler $
+# from: @(#)protocols 5.1 (Berkeley) 4/17/89
+#
+# See also http://www.iana.org/assignments/protocol-numbers
+#
+ip 0 IP # internet protocol, pseudo protocol number
+#hopopt 0 HOPOPT # hop-by-hop options for ipv6
+icmp 1 ICMP # internet control message protocol
+igmp 2 IGMP # internet group management protocol
+ggp 3 GGP # gateway-gateway protocol
+ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'')
+st2 5 ST2 # ST2 datagram mode (RFC 1819) (officially ``ST'')
+tcp 6 TCP # transmission control protocol
+cbt 7 CBT # CBT, Tony Ballardie <A.Ballardie@cs.ucl.ac.uk>
+egp 8 EGP # exterior gateway protocol
+igp 9 IGP # any private interior gateway (Cisco: for IGRP)
+bbn-rcc 10 BBN-RCC-MON # BBN RCC Monitoring
+nvp 11 NVP-II # Network Voice Protocol
+pup 12 PUP # PARC universal packet protocol
+argus 13 ARGUS # ARGUS
+emcon 14 EMCON # EMCON
+xnet 15 XNET # Cross Net Debugger
+chaos 16 CHAOS # Chaos
+udp 17 UDP # user datagram protocol
+mux 18 MUX # Multiplexing protocol
+dcn 19 DCN-MEAS # DCN Measurement Subsystems
+hmp 20 HMP # host monitoring protocol
+prm 21 PRM # packet radio measurement protocol
+xns-idp 22 XNS-IDP # Xerox NS IDP
+trunk-1 23 TRUNK-1 # Trunk-1
+trunk-2 24 TRUNK-2 # Trunk-2
+leaf-1 25 LEAF-1 # Leaf-1
+leaf-2 26 LEAF-2 # Leaf-2
+rdp 27 RDP # "reliable datagram" protocol
+irtp 28 IRTP # Internet Reliable Transaction Protocol
+iso-tp4 29 ISO-TP4 # ISO Transport Protocol Class 4
+netblt 30 NETBLT # Bulk Data Transfer Protocol
+mfe-nsp 31 MFE-NSP # MFE Network Services Protocol
+merit-inp 32 MERIT-INP # MERIT Internodal Protocol
+dccp 33 DCCP # Datagram Congestion Control Protocol
+3pc 34 3PC # Third Party Connect Protocol
+idpr 35 IDPR # Inter-Domain Policy Routing Protocol
+xtp 36 XTP # Xpress Tranfer Protocol
+ddp 37 DDP # Datagram Delivery Protocol
+idpr-cmtp 38 IDPR-CMTP # IDPR Control Message Transport Proto
+tp++ 39 TP++ # TP++ Transport Protocol
+il 40 IL # IL Transport Protocol
+ipv6 41 IPV6 # ipv6
+sdrp 42 SDRP # Source Demand Routing Protocol
+ipv6-route 43 IPV6-ROUTE # routing header for ipv6
+ipv6-frag 44 IPV6-FRAG # fragment header for ipv6
+idrp 45 IDRP # Inter-Domain Routing Protocol
+rsvp 46 RSVP # Resource ReSerVation Protocol
+gre 47 GRE # Generic Routing Encapsulation
+dsr 48 DSR # Dynamic Source Routing Protocol
+bna 49 BNA # BNA
+esp 50 ESP # encapsulating security payload
+ah 51 AH # authentication header
+i-nlsp 52 I-NLSP # Integrated Net Layer Security TUBA
+swipe 53 SWIPE # IP with Encryption
+narp 54 NARP # NBMA Address Resolution Protocol
+mobile 55 MOBILE # IP Mobility
+tlsp 56 TLSP # Transport Layer Security Protocol
+skip 57 SKIP # SKIP
+ipv6-icmp 58 IPV6-ICMP icmp6 # ICMP for IPv6
+ipv6-nonxt 59 IPV6-NONXT # no next header for ipv6
+ipv6-opts 60 IPV6-OPTS # destination options for ipv6
+# 61 # any host internal protocol
+cftp 62 CFTP # CFTP
+# 63 # any local network
+sat-expak 64 SAT-EXPAK # SATNET and Backroom EXPAK
+kryptolan 65 KRYPTOLAN # Kryptolan
+rvd 66 RVD # MIT Remote Virtual Disk Protocol
+ippc 67 IPPC # Internet Pluribus Packet Core
+# 68 # any distributed filesystem
+sat-mon 69 SAT-MON # SATNET Monitoring
+visa 70 VISA # VISA Protocol
+ipcv 71 IPCV # Internet Packet Core Utility
+cpnx 72 CPNX # Computer Protocol Network Executive
+cphb 73 CPHB # Computer Protocol Heart Beat
+wsn 74 WSN # Wang Span Network
+pvp 75 PVP # Packet Video Protocol
+br-sat-mon 76 BR-SAT-MON # Backroom SATNET Monitoring
+sun-nd 77 SUN-ND # SUN ND PROTOCOL-Temporary
+wb-mon 78 WB-MON # WIDEBAND Monitoring
+wb-expak 79 WB-EXPAK # WIDEBAND EXPAK
+iso-ip 80 ISO-IP # ISO Internet Protocol
+vmtp 81 VMTP # Versatile Message Transport
+secure-vmtp 82 SECURE-VMTP # SECURE-VMTP
+vines 83 VINES # VINES
+ttp 84 TTP # TTP
+#iptm 84 IPTM # Protocol Internet Protocol Traffic
+nsfnet-igp 85 NSFNET-IGP # NSFNET-IGP
+dgp 86 DGP # Dissimilar Gateway Protocol
+tcf 87 TCF # TCF
+eigrp 88 EIGRP # Enhanced Interior Routing Protocol (Cisco)
+ospf 89 OSPFIGP # Open Shortest Path First IGP
+sprite-rpc 90 Sprite-RPC # Sprite RPC Protocol
+larp 91 LARP # Locus Address Resolution Protocol
+mtp 92 MTP # Multicast Transport Protocol
+ax.25 93 AX.25 # AX.25 Frames
+ipip 94 IPIP # Yet Another IP encapsulation
+micp 95 MICP # Mobile Internetworking Control Pro.
+scc-sp 96 SCC-SP # Semaphore Communications Sec. Pro.
+etherip 97 ETHERIP # Ethernet-within-IP Encapsulation
+encap 98 ENCAP # Yet Another IP encapsulation
+# 99 # any private encryption scheme
+gmtp 100 GMTP # GMTP
+ifmp 101 IFMP # Ipsilon Flow Management Protocol
+pnni 102 PNNI # PNNI over IP
+pim 103 PIM # Protocol Independent Multicast
+aris 104 ARIS # ARIS
+scps 105 SCPS # SCPS
+qnx 106 QNX # QNX
+a/n 107 A/N # Active Networks
+ipcomp 108 IPComp # IP Payload Compression Protocol
+snp 109 SNP # Sitara Networks Protocol
+compaq-peer 110 Compaq-Peer # Compaq Peer Protocol
+ipx-in-ip 111 IPX-in-IP # IPX in IP
+carp 112 CARP vrrp # Common Address Redundancy Protocol
+pgm 113 PGM # PGM Reliable Transport Protocol
+# 114 # any 0-hop protocol
+l2tp 115 L2TP # Layer Two Tunneling Protocol
+ddx 116 DDX # D-II Data Exchange
+iatp 117 IATP # Interactive Agent Transfer Protocol
+stp 118 STP # Schedule Transfer Protocol
+srp 119 SRP # SpectraLink Radio Protocol
+uti 120 UTI # UTI
+smp 121 SMP # Simple Message Protocol
+sm 122 SM # SM
+ptp 123 PTP # Performance Transparency Protocol
+isis 124 ISIS # ISIS over IPv4
+fire 125 FIRE
+crtp 126 CRTP # Combat Radio Transport Protocol
+crudp 127 CRUDP # Combat Radio User Datagram
+sscopmce 128 SSCOPMCE
+iplt 129 IPLT
+sps 130 SPS # Secure Packet Shield
+pipe 131 PIPE # Private IP Encapsulation within IP
+sctp 132 SCTP # Stream Control Transmission Protocol
+fc 133 FC # Fibre Channel
+rsvp-e2e-ignore 134 RSVP-E2E-IGNORE # Aggregation of RSVP for IP reservations
+mobility-header 135 Mobility-Header # Mobility Support in IPv6
+udplite 136 UDPLite # The UDP-Lite Protocol
+mpls-in-ip 137 MPLS-IN-IP # Encapsulating MPLS in IP
+manet 138 MANET # MANET Protocols (RFC5498)
+hip 139 HIP # Host Identity Protocol (RFC5201)
+shim6 140 SHIM6 # Shim6 Protocol (RFC5533)
+wesp 141 WESP # Wrapped Encapsulating Security Payload (RFC5840)
+rohc 142 ROHC # Robust Header Compression (RFC5858)
+# 138-254 # Unassigned
+pfsync 240 PFSYNC # PF Synchronization
+# 253-254 # Use for experimentation and testing (RFC3692)
+# 255 # Reserved
+divert 258 DIVERT # Divert pseudo-protocol [non IANA]
diff --git a/src/etc/pubkey.pem b/src/etc/pubkey.pem
new file mode 100644
index 0000000..7dd575d
--- /dev/null
+++ b/src/etc/pubkey.pem
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAN08c22jym3KCRUF8/rKNXgU/J0vv6UC9eCta/ATTNgeW/z2rp/HsjcPkMLx9dLaqufShC0VzsUbGlqCsdQT8jfwBiLG2pjUkX20qTStRG/rs9Tv0rS/8eVNT/DbQ6zL3PTdp+XAIq+KQLucqcBazTqSzyF7ghZ7OVmsX1/ixTP3AAAAFQCYcP378X/dQ08l6u8O5uvEtxbvEwAAAIEAyOOuWttXGrprzBhKrjhop58bZTOZp0J0IMHMwi/J+K3HUuPZnaltGoW21MjqSvVor4m22r/3b8aUIom+jp4I/bmpxTOUgO6owTlCVX614fGPWcCw2M017aghQ/vUa/92DaMLO//FYD8X2b7WgyPNrJh9ckZ14oncBleJUfXmue8AAACBAKw00/IkoMJzTumFfT9+Jb442O1KZvtGyj1YWpyYXf3xbQFGXND7m4rTIS2zPvTcOauCHbZwZ9uBxE4zTdlGJ4XirPEbWwOl1TU71bZ3OqonVesyqSC04LLiuLGlIHyXxyc/UCzg1UL8mCBlLzqmPUkJoL0ZINo8Raqip8WM63KM root@freebsd-nexus-computers.pfsense.org
diff --git a/src/etc/rc b/src/etc/rc
new file mode 100755
index 0000000..1215883
--- /dev/null
+++ b/src/etc/rc
@@ -0,0 +1,439 @@
+#!/bin/sh
+
+# $Id$
+
+# /etc/rc - master bootup script, invokes php setup
+# part of pfSense by Scott Ullrich
+# Copyright (C) 2004-2010 Scott Ullrich, All rights reserved.
+# originally based on m0n0wall (http://neon1.net/m0n0wall)
+# Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+# All rights reserved.
+
+#/bin/stty status '^T'
+#/bin/stty susp '^-' intr '^-' quit '^-'
+
+#trap : 2
+#trap : 3
+
+HOME=/
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
+export HOME PATH
+
+# Set our operating platform
+PLATFORM=`/bin/cat /etc/platform`
+
+# Set our current version
+version=`/bin/cat /etc/version`
+
+# Setup dumpdev/ddb/savecore"
+echo "Configuring crash dumps..."
+if [ "$PLATFORM" = "pfSense" ]; then
+ /etc/rc.dumpon
+fi
+
+# Setup ddb on all platforms. On full install it will save the dump, on NanoBSD it will print to console and auto-reboot.
+if [ ! -z "`sysctl -Nq debug.ddb.scripting.scripts`" ]; then
+ /sbin/ddb /etc/ddb.conf
+fi
+
+if [ -e /root/force_fsck ]; then
+ echo "Forcing filesystem(s) check..."
+ /sbin/fsck -y -F -t ufs
+fi
+
+if [ ! "${PLATFORM}" = "cdrom" ]; then
+ /sbin/fsck -p -F
+ FSCK_ACTION_NEEDED=0
+ case $? in
+ 0)
+ echo "Filesystems are clean, continuing..."
+ echo "Mounting filesystems..."
+ ;;
+ 8)
+ echo "Preen mode recommended running a check that will be performed now."
+ FSCK_ACTION_NEEDED=1
+ ;;
+ *)
+ echo "Stopping boot is recommended due to filesystem manual action needed, nevertheless it will be tried to repair the filesystem."
+ FSCK_ACTION_NEEDED=1
+ ;;
+ esac
+
+ if [ ${FSCK_ACTION_NEEDED} = 1 ]; then
+ echo "WARNING: Trying to recover filesystem from inconsistency..."
+ /sbin/fsck -yF
+ fi
+
+ /sbin/mount -a 2>/dev/null
+ mount_rc=$?
+ attempts=0
+ while [ ${mount_rc} -ne 0 -a ${attempts} -lt 3 ]; do
+ /sbin/fsck -yF
+ /sbin/mount -a 2>/dev/null
+ mount_rc=$?
+ attempts=$((attempts+1))
+ done
+
+ if [ "${PLATFORM}" = "nanobsd" ]; then
+ # XXX This script does need all filesystems rw!!!!
+ # Put this workaround for now until better ways are found.
+ /sbin/mount -u -w -o sync,noatime /
+ /sbin/mount -u -w -o sync,noatime /cf
+ fi
+
+ # If /conf is a directory, convert it to a symlink to /cf/conf
+ if [ -d "/conf" ]; then
+ # If item is not a symlink then rm and recreate
+ CONFPOINTSTO=`readlink /conf`
+ if ! test "x$CONFPOINTSTO" = "x/cf/conf"; then
+ /bin/rm -rf /conf
+ /bin/ln -s /cf/conf /conf
+ fi
+ fi
+
+ USE_MFS_TMPVAR=`/usr/bin/grep -c use_mfs_tmpvar /cf/conf/config.xml`
+ if [ "${PLATFORM}" = "nanobsd" ] || [ ${USE_MFS_TMPVAR} -gt 0 ]; then
+ /etc/rc.embedded
+ fi
+fi
+
+/bin/rm -f /root/force_fsck
+/bin/rm -f /root/TRIM_set
+/bin/rm -f /root/TRIM_unset
+
+if [ "${PLATFORM}" = "nanobsd" ]; then
+ /sbin/kldstat -qm zfs
+ if [ $? -eq 0 ]; then
+ /sbin/kldunload zfs
+ fi
+elif [ "$PLATFORM" = "pfSense" ]; then
+ # Handle ZFS read-only case
+ /sbin/kldstat -qm zfs
+ if [ $? -eq 0 ]; then
+ ZFSFSAVAILABLE=$(/sbin/zfs mount 2>/dev/null | wc -l)
+ if [ $ZFSFSAVAILABLE -eq 0 ]; then
+ /sbin/kldunload zfs
+ elif [ -f /usr/bin/grep ]; then
+ ZFSROOT=`/sbin/zfs mount | /usr/bin/grep ' /$' | /usr/bin/cut -d ' ' -f 1`
+ if [ "$ZFSROOT" != "" ]; then
+ /sbin/zfs set readonly=off $ZFSROOT
+ fi
+ fi
+ fi
+elif [ "${PLATFORM}" = "cdrom" ]; then
+ /etc/rc.cdrom
+fi
+
+# Disable APM on ATA drives. Leaving this on will kill drives long-term, especially laptop drives, by generating excessive Load Cycles.
+if [ -f /etc/rc.disable_hdd_apm ]; then
+ /etc/rc.disable_hdd_apm
+fi
+
+#Eject CD devices on 3G modems
+MANUFACTURER="huawei|zte"
+CDDEVICE=`dmesg |egrep -ie "($MANUFACTURER)" | awk -F: '/cd/ {print $1}'`
+if [ "$CDDEVICE" != "" ]; then
+ cdcontrol -f /dev/"$CDDEVICE" eject
+fi
+
+product=`/usr/bin/grep product_name /etc/inc/globals.inc | /usr/bin/cut -d'"' -f4`
+hideplatform=`/usr/bin/grep hideplatform /etc/inc/globals.inc | /usr/bin/wc -l`
+varrunpath=`/usr/bin/grep varrun_path /etc/inc/globals.inc | /usr/bin/cut -d'"' -f4`
+
+if [ "$PLATFORM" = "pfSense" ] && [ ${USE_MFS_TMPVAR} -eq 0 ]; then
+ /sbin/mdmfs -S -M -s 4m md $varrunpath
+fi
+
+if [ "$hideplatform" -gt "0" ]; then
+ platformbanner="" # hide the platform
+else
+ platformbanner=" on the '${PLATFORM}' platform"
+fi
+
+echo
+cat /etc/ascii-art/pfsense-logo-small.txt
+echo
+echo
+echo "Welcome to ${product} ${version} ${platformbanner} ..."
+echo
+
+/sbin/conscontrol mute off >/dev/null
+
+if [ "$PLATFORM" = "cdrom" ] ; then
+ # do nothing for cdrom platform
+elif [ "$PLATFORM" = "nanobsd" ] || [ ${USE_MFS_TMPVAR} -gt 0 ]; then
+ # Ensure that old-style PKG packages can be persistent across reboots
+ /bin/mkdir -p /root/var/db/pkg
+ /bin/rm -rf /var/db/pkg
+ /bin/ln -s /root/var/db/pkg/ /var/db/pkg
+ # Ensure that PBI packages can be persistent across reboots
+ /bin/mkdir -p /root/var/db/pbi
+ /bin/rm -rf /var/db/pbi
+ /bin/ln -s /root/var/db/pbi/ /var/db/pbi
+else
+ SWAPDEVICE=`/bin/cat /etc/fstab | /usr/bin/grep swap | /usr/bin/cut -f1`
+ /sbin/swapon -a 2>/dev/null >/dev/null
+ /etc/rc.savecore
+
+ if [ -d /root/var/db/pkg ]; then
+ # User must have just disabled RAM disks, move these back into place.
+ /bin/mkdir -p /var/db/pkg
+ /bin/mv /root/var/db/pkg /var/db/pkg
+ /bin/mkdir -p /var/db/pbi
+ /bin/mv /root/var/db/pbi /var/db/pbi
+ fi
+fi
+
+# Copy PBI keys
+if ls /usr/local/share/pbi-keys/*.ssl >/dev/null 2>&1; then
+ if [ ! -d "/var/db/pbi/keys" ]; then
+ mkdir -p /var/db/pbi/keys
+ fi
+ cp -f /usr/local/share/pbi-keys/*.ssl /var/db/pbi/keys
+fi
+
+if [ "$PLATFORM" = "cdrom" ] ; then
+ echo -n "Mounting unionfs directories..."
+ /bin/mkdir /tmp/unionfs
+ /bin/mkdir /tmp/unionfs/usr
+ /bin/mkdir /tmp/unionfs/root
+ /bin/mkdir /tmp/unionfs/sbin
+ /bin/mkdir /tmp/unionfs/bin
+ /bin/mkdir /tmp/unionfs/boot
+ /bin/mkdir /tmp/unionfs/confdefault
+ /sbin/mount_unionfs /tmp/unionfs/usr /usr/
+ /sbin/mount_unionfs /tmp/unionfs/root /root/
+ /sbin/mount_unionfs /tmp/unionfs/bin /bin/
+ /sbin/mount_unionfs /tmp/unionfs/sbin /sbin/
+ /sbin/mount_unionfs /tmp/unionfs/boot /boot/
+ /sbin/mount_unionfs /tmp/unionfs/confdefault /conf.default/
+ echo "done."
+fi
+
+# make some directories in /var
+/bin/mkdir -p $varrunpath /var/log /var/etc /var/db/entropy /var/db/rrd /var/at/jobs/ /var/empty 2>/dev/null
+/bin/rm -rf $varrunpath/*
+if [ "$PLATFORM" != "pfSense" ]; then
+ /bin/rm /var/log/* 2>/dev/null
+fi
+
+# Cleanup configuration files from previous instance
+/bin/rm -rf /var/etc/*
+
+echo -n "Creating symlinks..."
+# Repair symlinks if they are broken
+if [ -f /etc/newsyslog.conf ]; then
+ /bin/rm -f /etc/newsyslog.conf
+fi
+if [ ! -L /etc/syslog.conf ]; then
+ /bin/rm -rf /etc/syslog.conf
+ if [ ! -f /var/etc/syslog.conf ]; then
+ touch /var/etc/syslog.conf
+ fi
+ /bin/ln -s /var/etc/syslog.conf /etc/syslog.conf
+fi
+
+# Repair symlinks if they are broken
+if [ ! -L /etc/hosts ]; then
+ /bin/rm -rf /etc/hosts
+ /bin/ln -s /var/etc/hosts /etc/hosts
+fi
+
+if [ ! -L /etc/resolv.conf ]; then
+ /bin/rm -rf /etc/resolv.conf
+ /bin/ln -s /var/etc/resolv.conf /etc/resolv.conf
+fi
+
+if [ ! -L /etc/resolvconf.conf ]; then
+ /bin/rm -rf /etc/resolvconf.conf
+ /bin/ln -s /var/etc/resolvconf.conf /etc/resolvconf.conf
+fi
+
+# Setup compatibility link for packages that
+# have trouble overriding the PREFIX configure
+# argument since we build our packages in a
+# separated PREFIX area
+# Only create if symlink does not exist.
+if [ ! -h /tmp/tmp ]; then
+ /bin/ln -hfs / /tmp/tmp
+fi
+
+# Make sure our /tmp is 777 + Sticky
+if [ ! "$PLATFORM" = "cdrom" ] ; then
+ /bin/rm -rf /tmp/*
+fi
+/bin/chmod 1777 /tmp
+
+if [ ! "$PLATFORM" = "cdrom" ] ; then
+ # Malloc debugging check
+ if [ -L /etc/malloc.conf ]; then
+ #ln -s aj /etc/malloc.conf
+ /bin/rm /etc/malloc.conf
+ fi
+fi
+
+if [ ! -L /etc/dhclient.conf ]; then
+ /bin/rm -rf /etc/dhclient.conf
+fi
+
+if [ ! -d /var/tmp ]; then
+ /bin/mkdir -p /var/tmp
+fi
+
+if [ ! -d /cf/conf/backup/ ]; then
+ /bin/mkdir -p /cf/conf/backup/
+fi
+
+set -T
+trap "echo 'Reboot interrupted'; exit 1" 3
+
+# Remove old nameserver resolution files
+/bin/rm -f /var/etc/nameserver*
+
+echo -n "."
+DISABLESYSLOGCLOG=`/usr/bin/grep -c disablesyslogclog /cf/conf/config.xml`
+ENABLEFIFOLOG=`/usr/bin/grep -c usefifolog /cf/conf/config.xml`
+LOG_FILES="system filter dhcpd vpn pptps poes l2tps openvpn portalauth ipsec ppp relayd wireless lighttpd ntpd gateways resolver routing"
+
+DEFAULT_LOG_FILE_SIZE=`/usr/local/bin/xmllint --xpath 'string(//pfsense/syslog/logfilesize)' /conf/config.xml`
+if [ ! ${DEFAULT_LOG_FILE_SIZE} ]; then
+ DEFAULT_LOG_FILE_SIZE=511488
+fi
+
+for logfile in $LOG_FILES; do
+ if [ "$DISABLESYSLOGCLOG" -gt "0" ]; then
+ /usr/bin/touch /var/log/$logfile.log
+ else
+ if [ ! -f /var/log/$logfile.log ]; then
+ if [ "$ENABLEFIFOLOG" -gt "0" ]; then
+ # generate fifolog files
+ /usr/sbin/fifolog_create -s ${DEFAULT_LOG_FILE_SIZE} /var/log/$logfile.log
+ else
+ /usr/local/sbin/clog -i -s ${DEFAULT_LOG_FILE_SIZE} /var/log/$logfile.log
+ fi
+ fi
+ fi
+done
+
+# change permissions on newly created fifolog files.
+/bin/chmod 0600 /var/log/*.log
+
+echo -n "."
+DEVFS=`/sbin/mount | /usr/bin/grep devfs | /usr/bin/wc -l | /usr/bin/cut -d" " -f8`
+if [ "$DEVFS" = "0" ]; then
+ mount_devfs devfs /dev
+fi
+
+# Create an initial utmp file
+cd $varrunpath && /bin/cp /dev/null utmp && /bin/chmod 644 utmp
+
+echo -n "."
+/sbin/ldconfig -elf /usr/lib /usr/local/lib /lib
+/etc/rc.d/ldconfig start 2>/dev/null
+
+# Launching kbdmux(4)
+if [ -f "/dev/kbdmux0" ]; then
+ echo -n "."
+ /usr/sbin/kbdcontrol -k /dev/kbdmux0 < /dev/console
+ [ -c "/dev/atkbd0" ] && kbdcontrol -a atkbd0 < /dev/console
+ [ -c "/dev/ukbd0" ] && kbdcontrol -a ukbd0 < /dev/console
+fi
+
+# Fire up unionfs if mount points exist.
+if [ -f /dist/uniondirs ]; then
+ echo -n "."
+ /etc/rc.d/unionfs start
+fi
+
+echo "done."
+
+# Recreate capabilities DB
+/usr/bin/cap_mkdb /etc/login.conf
+
+# Run the php.ini setup file and populate
+# /usr/local/etc/php.ini and /usr/local/lib/php.ini
+/etc/rc.php_ini_setup 2>/tmp/php_errors.txt
+/usr/local/sbin/php-fpm -c /usr/local/lib/php.ini -y /usr/local/lib/php-fpm.conf -RD 2>&1 >/dev/null
+
+# Launch external configuration loader for supported platforms
+if [ "$PLATFORM" = "nanobsd" ]; then
+ /usr/local/sbin/fcgicli -f /etc/ecl.php
+fi
+
+# Launch external configuration loader for supported platforms
+if [ "$PLATFORM" = "pfSense" ]; then
+ /usr/local/sbin/fcgicli -f /etc/ecl.php
+fi
+
+if [ -f /etc/rc.custom_boot_early ]; then
+ /bin/echo -n "Launching /etc/rc.custom_boot_early...";
+ /etc/rc.custom_boot_early
+ echo "Done"
+fi
+
+export fcgipath=/var/run/php-fpm.socket
+/usr/bin/nice -n20 /usr/local/sbin/check_reload_status
+
+# let the PHP-based configuration subsystem set up the system now
+echo -n "Launching the init system..."
+/bin/rm -f /cf/conf/backup/backup.cache
+/bin/rm -f /root/lighttpd*
+/usr/bin/touch $varrunpath/booting
+
+if [ "${PLATFORM}" = "nanobsd" ]; then
+ # XXX This script does need all filesystems rw!!!!
+ # Put this workaround for now until better ways are found.
+ /sbin/mount -u -f -r -o sync,noatime /
+ /sbin/mount -u -f -r -o sync,noatime /cf
+fi
+
+/etc/rc.bootup
+
+# /etc/rc.bootup unset $g['booting'], and removes file
+# Be sure the file is removed to not create troubles after
+if [ -f $varrunpath/booting ]; then
+ /bin/rm $varrunpath/booting
+fi
+
+echo -n "Starting CRON... "
+cd /tmp && /usr/sbin/cron -s 2>/dev/null
+echo "done."
+
+# Start packages
+/usr/local/sbin/fcgicli -f /etc/rc.start_packages
+
+/bin/rm -rf /usr/local/pkg/pf/CVS
+
+# Start ping handler every 240 seconds
+/usr/local/bin/minicron 240 $varrunpath/ping_hosts.pid /usr/local/bin/ping_hosts.sh
+
+# Start account expire handler every hour
+/usr/local/bin/minicron 3600 $varrunpath/expire_accounts.pid '/usr/local/sbin/fcgicli -f /etc/rc.expireaccounts'
+
+# Start alias url updater every 24 hours
+/usr/local/bin/minicron 86400 $varrunpath/update_alias_url_data.pid '/usr/local/sbin/fcgicli -f /etc/rc.update_alias_url_data'
+
+/bin/chmod a+rw /tmp/.
+
+# Check for GEOM mirrors
+GMIRROR_STATUS=`/sbin/gmirror status`
+if [ "${GMIRROR_STATUS}" != "" ]; then
+ # Using a flag file at bootup saves an expensive exec/check on each page load.
+ /usr/bin/touch /var/run/gmirror_active
+ # Setup monitoring/notifications
+ /usr/local/bin/minicron 60 /var/run/gmirror_status_check.pid /usr/local/sbin/gmirror_status_check.php
+fi
+
+# Log product version to syslog
+BUILDTIME=`cat /etc/version.buildtime`
+ARCH=`uname -m`
+echo "$product ($PLATFORM) $version $ARCH $BUILDTIME"
+
+echo "Bootup complete"
+
+/usr/local/bin/beep.sh start 2>&1 >/dev/null
+
+# Reset the cache. read-only requires this.
+/bin/rm -f /tmp/config.cache
+
+exit 0
diff --git a/src/etc/rc.backup_dhcpleases.sh b/src/etc/rc.backup_dhcpleases.sh
new file mode 100755
index 0000000..73f83a8
--- /dev/null
+++ b/src/etc/rc.backup_dhcpleases.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Save the DHCP lease database to the config path.
+if [ -d "/var/dhcpd/var/db" ]; then
+ /etc/rc.conf_mount_rw
+ cd / && tar -czf /cf/conf/dhcpleases.tgz -C / var/dhcpd/var/db/
+ /etc/rc.conf_mount_ro
+fi
diff --git a/src/etc/rc.backup_rrd.sh b/src/etc/rc.backup_rrd.sh
new file mode 100755
index 0000000..c14ffc7
--- /dev/null
+++ b/src/etc/rc.backup_rrd.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+: ${RRDDBPATH:=/var/db/rrd}
+: ${CF_CONF_PATH:=/cf/conf}
+
+# Save the rrd databases to the config path.
+if [ -d "${RRDDBPATH}" ]; then
+ [ -z "$NO_REMOUNT" ] && /etc/rc.conf_mount_rw
+ [ -f "${CF_CONF_PATH}/rrd.tgz" ] && /bin/rm -f "${CF_CONF_PATH}"/rrd.tgz
+
+ tgzlist=""
+
+ for rrdfile in "${RRDDBPATH}"/*.rrd ; do
+ xmlfile="${rrdfile%.rrd}.xml"
+ tgzfile="${rrdfile%.rrd}.tgz"
+ /usr/bin/nice -n20 /usr/local/bin/rrdtool dump "$rrdfile" "$xmlfile"
+ cd / && /usr/bin/tar -czf "${tgzfile}" -C / "${RRDDBPATH#/}"/*.xml
+ /bin/rm -f "${RRDDBPATH}"/*.xml
+ tgzlist="${tgzlist} @${tgzfile}"
+ done
+ if [ -n "${tgzlist}" ]; then
+ cd / && /usr/bin/tar -czf "${CF_CONF_PATH}/rrd.tgz" ${tgzlist}
+ /bin/rm -f "${RRDDBPATH}"/*.tgz
+ fi
+ [ -z "$NO_REMOUNT" ] && /etc/rc.conf_mount_ro
+fi
+
diff --git a/src/etc/rc.banner b/src/etc/rc.banner
new file mode 100755
index 0000000..5e64dae
--- /dev/null
+++ b/src/etc/rc.banner
@@ -0,0 +1,123 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ $Id$
+
+ rc.banner
+ part of pfSense
+ Copyright (C) 2005 Scott Ullrich and Colin Smith
+ Copyright (C) 2009 Ermal Luçi
+ All rights reserved
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("gwlb.inc");
+ require_once("interfaces.inc");
+
+ $platform = trim(file_get_contents("{$g['etc_path']}/platform"));
+ $hostname = $config['system']['hostname'];
+ $product = $g['product_name'];
+ $machine = trim(`uname -m`);
+ $hideplatform = $g['hideplatform'];
+
+ if (!$hideplatform) {
+ $platformbanner = "-{$platform}";
+ }
+
+ print "*** Welcome to {$product} {$g['product_version']}{$platformbanner} ({$machine}) on {$hostname} ***\n";
+
+ $iflist = get_configured_interface_with_descr(false, true);
+ foreach ($iflist as $ifname => $friendly) {
+ /* point to this interface's config */
+ $ifconf = $config['interfaces'][$ifname];
+ /* look for 'special cases' */
+ switch ($ifconf['ipaddr']) {
+ case "dhcp":
+ $class = "/DHCP4";
+ break;
+ case "pppoe":
+ $class = "/PPPoE";
+ break;
+ case "pptp":
+ $class = "/PPTP";
+ break;
+ case "l2tp":
+ $class = "/L2TP";
+ break;
+ default:
+ $class = "";
+ break;
+ }
+ switch ($ifconf['ipaddrv6']) {
+ case "dhcp6":
+ $class6 = "/DHCP6";
+ break;
+ case "slaac":
+ $class6 = "/SLAAC";
+ break;
+ case "6rd":
+ $class6 = "/6RD";
+ break;
+ case "6to4":
+ $class6 = "/6to4";
+ break;
+ case "track6":
+ $class6 = "/t6";
+ break;
+ }
+ $ipaddr = get_interface_ip($ifname);
+ $subnet = get_interface_subnet($ifname);
+ $ipaddr6 = get_interface_ipv6($ifname);
+ $subnet6 = get_interface_subnetv6($ifname);
+ $realif = get_real_interface($ifname);
+ $tobanner = "{$friendly} ({$ifname})";
+
+ printf("\n %-15s -> %-10s -> ",
+ $tobanner,
+ $realif
+ );
+ $v6first = false;
+ if (!empty($ipaddr) && !empty($subnet)) {
+ printf("v4%s: %s/%s",
+ $class,
+ $ipaddr,
+ $subnet
+ );
+ } else {
+ $v6first = true;
+ }
+ if (!empty($ipaddr6) && !empty($subnet6)) {
+ if (!$v6first) {
+ printf("\n%s", str_repeat(" ", 34));
+ }
+ printf("v6%s: %s/%s",
+ $class6,
+ $ipaddr6,
+ $subnet6
+ );
+ }
+ }
+ printf("\n");
+?>
diff --git a/src/etc/rc.bootup b/src/etc/rc.bootup
new file mode 100755
index 0000000..d27f795
--- /dev/null
+++ b/src/etc/rc.bootup
@@ -0,0 +1,428 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.bootup
+ part of pfSense by Scott Ullrich
+ originally based on m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2004-2009 Scott Ullrich <sullrich@pfsense.org>.
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2009 Erik Kristensen
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+function rescue_detect_keypress() {
+ // How long do you want the script to wait before moving on (in seconds)
+ $timeout=9;
+ echo "\n";
+ echo "[ Press R to enter recovery mode or ]\n";
+ echo "[ press I to launch the installer ]\n\n";
+ echo "(R)ecovery mode can assist by rescuing config.xml\n";
+ echo "from a broken hard disk installation, etc.\n\n";
+ echo "(I)nstaller will be invoked\n\n";
+ echo "Timeout before auto boot continues (seconds): {$timeout}";
+ $key = null;
+ exec("/bin/stty erase " . chr(8));
+ while (!in_array($key, array("r", "R", "i", "I"))) {
+ echo chr(8) . "{$timeout}";
+ `/bin/stty -icanon min 0 time 25`;
+ $key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
+ `/bin/stty icanon`;
+ // Decrement our timeout value
+ $timeout--;
+ // If we have reached 0 exit and continue on
+ if ($timeout == 0) {
+ break;
+ }
+ }
+ // If R or I was pressed do our logic here
+ if (in_array($key, array("r", "R"))) {
+ putenv("TERM=cons25");
+ echo "\n\nRecovery mode selected...\n";
+ passthru("/usr/bin/env TERM=cons25 /bin/tcsh -c /scripts/lua_installer rescue");
+ } else {
+ putenv("TERM=cons25");
+ echo "\n\nInstaller mode selected...\n";
+ passthru("/usr/bin/env TERM=cons25 /bin/tcsh -c /scripts/lua_installer");
+ }
+
+ passthru("/etc/rc.reboot");
+ exit;
+}
+
+echo " done.\n";
+
+echo "Initializing...";
+echo ".";
+require_once("/etc/inc/globals.inc");
+echo ".";
+require_once("/etc/inc/led.inc");
+led_normalize();
+echo ".";
+if (led_count() >= 3) {
+ led_kitt();
+}
+
+/* let the other functions know we're booting */
+$pkg_interface = 'console';
+$g['booting'] = true;
+
+/* parse the configuration and include all functions used below */
+require_once("/etc/inc/config.inc");
+echo ".";
+require_once("/etc/inc/config.console.inc");
+echo ".";
+require_once("/etc/inc/auth.inc");
+echo ".";
+require_once("/etc/inc/functions.inc");
+echo ".";
+require_once("/etc/inc/filter.inc");
+echo ".";
+require_once("/etc/inc/shaper.inc");
+echo ".";
+require_once("/etc/inc/ipsec.inc");
+echo ".";
+require_once("/etc/inc/vpn.inc");
+echo ".";
+require_once("/etc/inc/openvpn.inc");
+echo ".";
+require_once("/etc/inc/captiveportal.inc");
+echo ".";
+require_once("/etc/inc/rrd.inc");
+echo ".";
+require_once("/etc/inc/pfsense-utils.inc");
+echo ".";
+
+/* get system memory amount */
+$memory = get_memory();
+$physmem = $memory[0];
+$realmem = $memory[1];
+echo " done.\n";
+
+conf_mount_rw();
+
+/* save dmesg output to file */
+system_dmesg_save();
+
+/* check whether config reset is desired (via hardware button on WRAP/ALIX) */
+system_check_reset_button();
+
+/* remove previous firmware upgrade if present */
+if (file_exists("/root/firmware.tgz")) {
+ unlink("/root/firmware.tgz");
+}
+
+/* start devd (dhclient now uses it) */
+echo "Starting device manager (devd)...";
+mute_kernel_msgs();
+start_devd();
+set_device_perms();
+unmute_kernel_msgs();
+echo "done.\n";
+
+// Display rescue configuration option
+if ($g['platform'] == "cdrom") {
+ rescue_detect_keypress();
+}
+
+echo "Loading configuration...";
+parse_config_bootup();
+echo "done.\n";
+
+/*
+ * Determine if we need to throw a interface exception
+ * and ask the user to reassign interfaces. This will
+ * avoid a reboot and that is a good thing.
+ */
+while (is_interface_mismatch() == true) {
+ led_assigninterfaces();
+ if (isset($config['revision'])) {
+ if (file_exists("{$g['tmp_path']}/missing_interfaces")) {
+ echo "Warning: Configuration references interfaces that do not exist: " . file_get_contents("{$g['tmp_path']}/missing_interfaces") . "\n";
+ }
+ echo "\nNetwork interface mismatch -- Running interface assignment option.\n";
+ } else {
+ echo "\nDefault interfaces not found -- Running interface assignment option.\n";
+ }
+ $ifaces = get_interface_list();
+ if (is_array($ifaces)) {
+ foreach ($ifaces as $iface => $ifdata) {
+ interfaces_bring_up($iface);
+ }
+ }
+ set_networking_interfaces_ports();
+ led_kitt();
+}
+
+/* convert config and clean backups */
+echo "Updating configuration...";
+convert_config();
+echo "done.\n";
+
+echo "Cleaning backup cache...";
+cleanup_backupcache(true);
+echo "done.\n";
+
+/* read in /etc/sysctl.conf and set values if needed */
+echo "Setting up extended sysctls...";
+system_setup_sysctl();
+echo "done.\n";
+
+/* enable optional crypto modules */
+load_crypto();
+
+/* enable optional thermal sensor modules */
+load_thermal_hardware();
+
+/* run any early shell commands specified in config.xml */
+system_do_shell_commands(1);
+
+/* set up our timezone */
+system_timezone_configure();
+
+/* set up our hostname */
+system_hostname_configure();
+
+/* make hosts file */
+system_hosts_generate();
+
+/* configure loopback interface */
+interfaces_loopback_configure();
+
+/* start syslogd */
+system_syslogd_start();
+
+echo "Starting Secure Shell Services...";
+send_event("service reload sshd");
+echo "done.\n";
+
+/* setup polling */
+echo "Setting up polling defaults...";
+setup_polling();
+echo "done.\n";
+
+/* setup interface microcode which improves tcp/ip speed */
+echo "Setting up interfaces microcode...";
+setup_microcode();
+echo "done.\n";
+
+/* set up interfaces */
+if (!$debugging) {
+ mute_kernel_msgs();
+}
+interfaces_configure();
+interfaces_sync_setup();
+if (!$debugging) {
+ unmute_kernel_msgs();
+}
+
+/* re-make hosts file after configuring interfaces */
+system_hosts_generate();
+
+/* start OpenVPN server & clients */
+echo "Syncing OpenVPN settings...";
+openvpn_resync_all();
+echo "done.\n";
+
+/* generate resolv.conf */
+system_resolvconf_generate();
+
+/* setup altq + pf */
+filter_configure_sync();
+
+/* start pflog */
+echo "Starting PFLOG...";
+filter_pflog_start();
+echo "done.\n";
+
+/* reconfigure our gateway monitor */
+echo "Setting up gateway monitors...";
+setup_gateways_monitor();
+echo "done.\n";
+
+echo "Synchronizing user settings...";
+local_sync_accounts();
+echo "done.\n";
+
+if ($realmem > 0 and $realmem < 65) {
+ echo "System has less than 65 megabytes of ram {$realmem}. Delaying webConfigurator startup.\n";
+ /* start webConfigurator up on final pass */
+ mwexec("/usr/local/sbin/pfSctl -c 'service restart webgui'");
+} else {
+ /* start web server */
+ system_webgui_start();
+}
+
+/* configure cron service */
+echo "Configuring CRON...";
+configure_cron();
+echo "done.\n";
+
+/* set up static routes */
+system_routing_configure();
+
+/* enable routing */
+system_routing_enable();
+
+/* start dnsmasq service */
+services_dnsmasq_configure();
+
+/* start unbound service */
+services_unbound_configure();
+
+/* Do an initial time sync */
+echo "Starting NTP time client...";
+/* At bootup this will just write the config, ntpd will launch from ntpdate_sync_once.sh */
+system_ntp_configure(false);
+mwexec_bg("/usr/local/sbin/ntpdate_sync_once.sh", true);
+echo "done.\n";
+
+/* start load balancer daemon */
+relayd_configure();
+
+/* configure console menu */
+system_console_configure();
+
+/* start DHCP service */
+services_dhcpd_configure();
+
+/* start dhcpleases dhcp hosts leases program */
+system_dhcpleases_configure();
+
+/* start DHCP relay */
+services_dhcrelay_configure();
+
+/* start DHCP6 relay */
+services_dhcrelay6_configure();
+
+/* dyndns service updates */
+send_event("service reload dyndnsall");
+
+/* Run a filter configure now that most all services have started */
+filter_configure_sync();
+
+/* setup pppoe and pptp */
+vpn_setup();
+
+/* start the captive portal */
+captiveportal_configure();
+
+/* start Voucher support */
+voucher_configure();
+
+/* run any shell commands specified in config.xml */
+system_do_shell_commands();
+
+/* start IPsec tunnels */
+$ipsec_dynamic_hosts = vpn_ipsec_configure();
+
+/* start SNMP service */
+services_snmpd_configure();
+
+/* power down hard drive if needed/set */
+system_set_harddisk_standby();
+
+/* lock down console if necessary */
+reload_ttys();
+
+/* load graphing functions */
+enable_rrd_graphing();
+
+/* enable watchdog if supported */
+enable_watchdog();
+
+/* if <system><afterbootupshellcmd> exists, execute the command */
+if ($config['system']['afterbootupshellcmd'] <> "") {
+ echo "Running afterbootupshellcmd {$config['system']['afterbootupshellcmd']}\n";
+ mwexec($config['system']['afterbootupshellcmd']);
+}
+
+if ($physmem < $g['minimum_ram_warning']) {
+ require_once("/etc/inc/notices.inc");
+ file_notice("{$g['product_name']}MemoryRequirements", "{$g['product_name']} requires at least {$g['minimum_ram_warning_text']} of RAM. Expect unusual performance. This platform is not supported.", "Memory", "", 1);
+ set_sysctl(array(
+ "net.inet.tcp.recvspace" => "4096",
+ "net.inet.tcp.sendspace" => "4096"
+ ));
+}
+
+/* if we are operating at 1000 then increase timeouts.
+ this was never accounted for after moving to 1000 hz */
+$kern_hz = get_single_sysctl('kern.clockrate');
+$kern_hz = substr($kern_hz, strpos($kern_hz, "hz = ") + 5);
+$kern_hz = substr($kern_hz, 0, strpos($kern_hz, ","));
+if ($kern_hz == "1000") {
+ set_single_sysctl("net.inet.tcp.rexmit_min" , "30");
+}
+
+/* start the igmpproxy daemon */
+services_igmpproxy_configure();
+
+/* start the upnp daemon if it is enabled */
+upnp_start();
+
+/* If powerd is enabled, lets launch it */
+activate_powerd();
+
+/* Set preferred protocol */
+prefer_ipv4_or_ipv6();
+
+/* Remove the old shutdown binary if we kept it. */
+if (file_exists("/sbin/shutdown.old")) {
+ @unlink("/sbin/shutdown.old");
+}
+
+/* Resync / Reinstall packages if need be */
+if (file_exists('/conf/needs_package_sync')) {
+ if ($config['installedpackages'] <> '' && is_array($config['installedpackages']['package'])) {
+ require_once("pkg-utils.inc");
+ if ($g['platform'] == "pfSense" || $g['platform'] == "nanobsd") {
+ mark_subsystem_dirty('packagelock');
+ pkg_reinstall_all();
+ clear_subsystem_dirty('packagelock');
+ }
+ }
+ @unlink('/conf/needs_package_sync');
+}
+
+/* Give syslogd a kick after everything else has been initialized, otherwise it can occasionally
+ fail to route syslog messages properly on both IPv4 and IPv6 */
+system_syslogd_start();
+
+/* done */
+unset($g['booting']);
+@unlink("{$g['varrun_path']}/booting");
+
+/* If there are ipsec dynamic hosts try again to reload the tunnels as rc.newipsecdns does */
+if ($ipsec_dynamic_hosts) {
+ vpn_ipsec_configure();
+}
+if ($ipsec_dynamic_hosts || !empty($filterdns)) {
+ filter_configure();
+}
+
+led_normalize();
+
+conf_mount_ro();
+
+?>
diff --git a/src/etc/rc.captiveportal_configure b/src/etc/rc.captiveportal_configure
new file mode 100755
index 0000000..45c26bf
--- /dev/null
+++ b/src/etc/rc.captiveportal_configure
@@ -0,0 +1,40 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.captiveportal_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require("config.inc");
+require("functions.inc");
+require_once("filter.inc");
+require("shaper.inc");
+require("captiveportal.inc");
+
+captiveportal_configure();
+
+?>
diff --git a/src/etc/rc.captiveportal_configure_mac b/src/etc/rc.captiveportal_configure_mac
new file mode 100755
index 0000000..b0daf68
--- /dev/null
+++ b/src/etc/rc.captiveportal_configure_mac
@@ -0,0 +1,52 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.captiveportal_configure_mac
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2015 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require("config.inc");
+require("functions.inc");
+require_once("filter.inc");
+require("shaper.inc");
+require("captiveportal.inc");
+
+global $cpzone;
+
+$cpzone = isset($_GET['cpzone']) ? $_GET['cpzone'] : trim($argv[1]);
+$startidx = isset($_GET['startidx']) ? $_GET['startidx'] : trim($argv[2]);
+$stopidx = isset($_GET['cpzone']) ? $_GET['stopidx'] : trim($argv[3]);
+
+$cpzoneidx = $config['captiveportal'][$cpzone]['zoneid'];
+$filename = "{$g['tmp_path']}/{$cpzoneidx}_mac_{$startidx}_{$stopidx}";
+
+//log_error("STARTED: " . time() . " - {$cpzone} : $startidx : {$stopidx} : {$cpzoneidx} : {$filename}");
+captiveportal_passthrumac_configure($filename, $startidx, $stopidx);
+//log_error("STOPPED: " .time() . " - {$cpzone} : $startidx : {$stopidx} : {$cpzoneidx} : {$filename}");
+
+mwexec("/sbin/ipfw -x {$cpzoneidx} -q {$filename}");
+@unlink($filename);
+?>
diff --git a/src/etc/rc.carpbackup b/src/etc/rc.carpbackup
new file mode 100755
index 0000000..6961bc8
--- /dev/null
+++ b/src/etc/rc.carpbackup
@@ -0,0 +1,97 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.carpbackup
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("functions.inc");
+require_once("config.inc");
+require_once("notices.inc");
+require_once("openvpn.inc");
+require_once("interfaces.inc");
+
+if (isset($_GET)) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = str_replace("\n", "", $argv[1]);
+}
+if (!strstr($argument, "@")) {
+ log_error("Carp MASTER event triggered from wrong source {$argument}");
+}
+
+list($vhid, $iface) = explode("@", $argument);
+
+$friendly = convert_real_interface_to_friendly_interface_name($iface);
+$friendly_descr = convert_friendly_interface_to_friendly_descr($friendly);
+$vips = link_interface_to_vips($friendly, '', $vhid);
+$carp_iface = "{$friendly}_vip{$vhid}";
+foreach ($vips as $vip) {
+ $notificationmsg = sprintf('Carp cluster member "{$friendly_descr)(%2$s): {$vip['subnet']} (%1$s)" has resumed the state "BACKUP" for vhid %s', $argument, $vip['descr'], $vhid);
+
+ notify_via_smtp($notificationmsg);
+ notify_via_growl($notificationmsg);
+ log_error($notificationmsg);
+}
+
+/* Stop OpenVPN clients running on this VIP, since multiple active OpenVPN clients on a CARP cluster can be problematic. */
+global $config;
+if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as $settings) {
+ foreach ($vips as $vip) {
+ if ($settings['interface'] == "_vip{$vip['uniqid']}") {
+ log_error("Stopping OpenVPN client instance on {$friendly_descr} because of transition to CARP backup.");
+ openvpn_restart('client', $settings);
+ }
+ }
+ }
+}
+
+/* Reconfigure radvd when necessary */
+if (isset($config['dhcpdv6']) && is_array($config['dhcpdv6'])) {
+ $found = false;
+ foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
+ if ($dhcpv6ifconf['rainterface'] != $carp_iface) {
+ continue;
+ }
+
+ $found = true;
+ break;
+ }
+
+ if ($found === true) {
+ services_radvd_configure();
+ }
+}
+
+$pluginparams = array();
+$pluginparams['type'] = 'carp';
+$pluginparams['event'] = 'rc.carpbackup';
+$pluginparams['interface'] = $argument;
+pkg_call_plugins('plugin_carp', $pluginparams);
+
+?>
diff --git a/src/etc/rc.carpmaster b/src/etc/rc.carpmaster
new file mode 100755
index 0000000..022fe8f
--- /dev/null
+++ b/src/etc/rc.carpmaster
@@ -0,0 +1,105 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.carpmaster
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("functions.inc");
+require_once("config.inc");
+require_once("notices.inc");
+require_once("openvpn.inc");
+require_once("interfaces.inc");
+
+if (isset($_GET)) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = str_replace("\n", "", $argv[1]);
+}
+if (!strstr($argument, "@")) {
+ log_error("Carp MASTER event triggered from wrong source {$argument}");
+}
+
+list($vhid, $iface) = explode("@", $argument);
+
+$friendly = convert_real_interface_to_friendly_interface_name($iface);
+$friendly_descr = convert_friendly_interface_to_friendly_descr($friendly);
+$vips = link_interface_to_vips($friendly, '', $vhid);
+$carp_iface = "{$friendly}_vip{$vhid}";
+foreach ($vips as $vip) {
+ $notificationmsg = sprintf('Carp cluster member "{$friendly_descr)(%2$s): {$vip['subnet']} (%1$s)" has resumed the state "MASTER" for vhid %s', $argument, $vip['descr'], $vhid);
+
+ notify_via_smtp($notificationmsg);
+ notify_via_growl($notificationmsg);
+ log_error($notificationmsg);
+}
+
+/* Start OpenVPN clients running on this VIP, since they should be in the stopped state while the VIP is CARP Backup. */
+global $config;
+if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as $settings) {
+ foreach ($vips as $vip) {
+ if ($settings['interface'] == "_vip{$vip['uniqid']}") {
+ log_error("Starting OpenVPN client instance on {$friendly_descr} because of transition to CARP master.");
+ openvpn_restart('client', $settings);
+ }
+ }
+ }
+}
+if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as $settings) {
+ if ($settings['interface'] == $carp_iface) {
+ log_error("Starting OpenVPN instance on {$friendly_descr} because of transition to CARP master.");
+ openvpn_restart('server', $settings);
+ }
+ }
+}
+
+/* Reconfigure radvd when necessary */
+if (isset($config['dhcpdv6']) && is_array($config['dhcpdv6'])) {
+ $found = false;
+ foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
+ if ($dhcpv6ifconf['rainterface'] != $carp_iface) {
+ continue;
+ }
+
+ $found = true;
+ break;
+ }
+
+ if ($found === true) {
+ services_radvd_configure();
+ }
+}
+
+$pluginparams = array();
+$pluginparams['type'] = 'carp';
+$pluginparams['event'] = 'rc.carpmaster';
+$pluginparams['interface'] = $argument;
+pkg_call_plugins('plugin_carp', $pluginparams);
+
+?>
diff --git a/src/etc/rc.cdrom b/src/etc/rc.cdrom
new file mode 100755
index 0000000..5e8d80f
--- /dev/null
+++ b/src/etc/rc.cdrom
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# rc.cdrom - livedisc specific routines
+# For pfSense
+
+# Size of memory file system /cf/conf partition
+partsize="6m"
+
+export VARMFS_COPYDBPKG=yes
+
+for i in tmp varmfs etcmfs; do
+ if [ -f /etc/rc.d/$i ]; then
+ sh /etc/rc.d/$i start
+ fi
+done
+
+# Start PFI
+/bin/sh /scripts/pfi start
+
+# If PFI did not find a config, we should create
+# a tiny mfs under /cf/conf and populate with stock
+# configuration.
+if [ ! -f /conf/config.xml ]; then
+ echo -n "Generating a MFS /conf partition... "
+ device=$(mdconfig -a -t malloc -s ${partsize})
+ newfs /dev/${device} > /dev/null 2>&1
+ mount /dev/${device} /cf/conf
+ cp /conf.default/* /cf/conf
+ echo "done."
+fi
+
+echo -n "Generating a MFS /home partition... "
+device=$(mdconfig -a -t malloc -s ${partsize})
+newfs /dev/${device} > /dev/null 2>&1
+mount /dev/${device} /home
+echo "done."
+
+# Create some needed directories
+/bin/mkdir -p /var/tmp/vi.recover/
diff --git a/src/etc/rc.conf b/src/etc/rc.conf
new file mode 100644
index 0000000..01cd50f
--- /dev/null
+++ b/src/etc/rc.conf
@@ -0,0 +1 @@
+# THIS FILE DOES NOTHING, DO NOT MAKE CONFIG CHANGES HERE
diff --git a/src/etc/rc.conf_mount_ro b/src/etc/rc.conf_mount_ro
new file mode 100755
index 0000000..6beb5e8
--- /dev/null
+++ b/src/etc/rc.conf_mount_ro
@@ -0,0 +1,36 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.conf_mount_ro
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+
+conf_mount_ro();
+
+?>
diff --git a/src/etc/rc.conf_mount_rw b/src/etc/rc.conf_mount_rw
new file mode 100755
index 0000000..b153e36
--- /dev/null
+++ b/src/etc/rc.conf_mount_rw
@@ -0,0 +1,36 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.conf_mount_rw
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+
+conf_mount_rw();
+
+?>
diff --git a/src/etc/rc.create_full_backup b/src/etc/rc.create_full_backup
new file mode 100755
index 0000000..048e68b
--- /dev/null
+++ b/src/etc/rc.create_full_backup
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+FILENAME="pfSense-full-backup-`date "+%Y%m%d-%H%M"`.tgz"
+echo ">>> Creating full backup to /root/$FILENAME"
+tar czPf /root/$FILENAME \
+ --exclude dev/* \
+ --exclude tmp/* \
+ --exclude var/db \
+ --exclude var/run/* \
+ --exclude root/* \
+ --exclude var/empty/* \
+ --exclude var/empty \
+ --exclude var/etc \
+ /
+
+echo ">>> Backup completed. Note: this backup includes config.xml!"
+echo ">>> To restore this backup run this command:"
+echo " /etc/rc.restore_full_backup /root/$FILENAME"
diff --git a/src/etc/rc.d/etcmfs b/src/etc/rc.d/etcmfs
new file mode 100755
index 0000000..7e50427
--- /dev/null
+++ b/src/etc/rc.d/etcmfs
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Dario Freni
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+# $Id: etcmfs.rc,v 1.1.1.1 2008/03/25 19:58:16 sullrich Exp $
+#
+
+# PROVIDE: etcmfs
+# REQUIRE: mountcritlocal
+# BEFORE: var
+
+. /etc/rc.subr
+
+name="etcmfs"
+kenvetcsize=`kenv -q freesbie.etcsize`
+etcsize=${kenvetcsize:-"20m"}
+kenvlocaletcsize=`kenv -q freesbie.localetcsize`
+localetcsize=${kenvlocaletcsize:-"32m"}
+
+load_rc_config $name
+
+tempdir=/tmp
+
+echo "Generating MFS /etc partition"
+
+device=$(mdconfig -a -t malloc -o compress -s ${etcsize})
+bsdlabel -w ${device} auto
+newfs -n -m 2 /dev/${device} > /dev/null 2>&1
+mount -o noatime /dev/${device} ${tempdir}
+
+back=$PWD
+
+cd /etc
+find . -print -depth | cpio -dump --quiet ${tempdir}
+
+cd $back
+
+mtree -PUer -q -p ${tempdir} < /etc/mtree/etc.dist > /dev/null 2>&1
+
+umount ${tempdir}
+mount -o noatime /dev/${device} /etc
+
+if [ -f /etc/mtree/localetc.dist ]; then
+ device=$(mdconfig -a -t malloc -o compress -s ${localetcsize})
+ newfs /dev/${device} > /dev/null 2>&1
+ mount -o noatime /dev/${device} ${tempdir}
+
+ cd /usr/local/etc
+ find . -print -depth | cpio -dump --quiet ${tempdir}
+
+ cd $back
+
+ mtree -PUer -q -p ${tempdir} < /etc/mtree/localetc.dist > /dev/null 2>&1
+
+ umount ${tempdir}
+ mount -o noatime /dev/${device} /usr/local/etc
+fi
diff --git a/src/etc/rc.d/hostid b/src/etc/rc.d/hostid
new file mode 100755
index 0000000..37ea173
--- /dev/null
+++ b/src/etc/rc.d/hostid
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+# Copyright (c) 2015 Xin LI <delphij@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# PROVIDE: hostid
+# REQUIRE: sysctl
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="hostid"
+start_cmd="hostid_start"
+stop_cmd=":"
+reset_cmd="hostid_reset"
+extra_commands="reset"
+rcvar="hostid_enable"
+
+hostid_set()
+{
+ uuid=$1
+ # Generate hostid based on hostuuid - take first four bytes from md5(uuid).
+ id=`echo -n $uuid | /sbin/md5`
+ id="0x${id%????????????????????????}"
+
+ # Set both kern.hostuuid and kern.hostid.
+ #
+ check_startmsgs && echo "Setting hostuuid: ${uuid}."
+ ${SYSCTL} kern.hostuuid="${uuid}" >/dev/null
+ check_startmsgs && echo "Setting hostid: ${id}."
+ ${SYSCTL} kern.hostid=${id} >/dev/null
+}
+
+valid_hostid()
+{
+ uuid=$1
+
+ x="[0-9a-f]"
+ y=$x$x$x$x
+
+ # Check against a blacklist before
+ # accepting the UUID.
+ case "${uuid}" in
+ 00000000-0000-0000-0000-000000000000)
+ ;;
+ 00020003-0004-0005-0006-000700080009)
+ ;;
+ 03000200-0400-0500-0006-000700080009)
+ ;;
+ 07090201-0103-0301-0807-060504030201)
+ ;;
+ 11111111-1111-1111-1111-111111111111)
+ ;;
+ 11111111-2222-3333-4444-555555555555)
+ ;;
+ 4c4c4544-0000-2010-8020-80c04f202020)
+ ;;
+ 58585858-5858-5858-5858-585858585858)
+ ;;
+ 890e2d14-cacd-45d1-ae66-bc80e8bfeb0f)
+ ;;
+ 8e275844-178f-44a8-aceb-a7d7e5178c63)
+ ;;
+ dc698397-fa54-4cf2-82c8-b1b5307a6a7f)
+ ;;
+ fefefefe-fefe-fefe-fefe-fefefefefefe)
+ ;;
+ *-ffff-ffff-ffff-ffffffffffff)
+ ;;
+ $y$y-$y-$y-$y-$y$y$y)
+ return 0
+ ;;
+ esac
+
+ return 1
+}
+
+hostid_generate()
+{
+ # First look for UUID in hardware.
+ # If not found, fall back to software-generated UUID.
+ uuid=`uuidgen`
+ hostid_set $uuid
+}
+
+hostid_reset()
+{
+ hostid_generate
+ # Store newly generated UUID in ${hostid_file}.
+ echo $uuid > ${hostid_file}
+ if [ $? -ne 0 ]; then
+ warn "could not store hostuuid in ${hostid_file}."
+ fi
+}
+
+hostid_start()
+{
+ # If ${hostid_file} already exists, we take UUID from there.
+ if [ -r ${hostid_file} ]; then
+ read saved_hostid < ${hostid_file}
+ if valid_hostid ${saved_hostid}; then
+ hostid_set `cat ${hostid_file}`
+ exit 0
+ fi
+ fi
+
+ # No hostid file, generate UUID.
+ hostid_generate
+}
+
+load_rc_config $name
+run_rc_command "$1"
diff --git a/src/etc/rc.d/varmfs b/src/etc/rc.d/varmfs
new file mode 100755
index 0000000..2921a1a
--- /dev/null
+++ b/src/etc/rc.d/varmfs
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Dario Freni
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+# $Id: varmfs.rc,v 1.1.1.1 2008/03/25 19:58:16 sullrich Exp $
+#
+
+# PROVIDE: varmfs
+# REQUIRE: mountcritlocal
+# BEFORE: var
+
+. /etc/rc.subr
+
+name="varmfs"
+kenvvarsize=`kenv -q freesbie.varsize`
+varsize=${kenvvarsize:-"32m"}
+
+load_rc_config $name
+
+tempdir=/tmp
+
+echo "Generating MFS /var partition"
+
+device=$(mdconfig -a -t malloc -o compress -s ${varsize})
+bsdlabel -w ${device} auto
+newfs -n -m 2 /dev/${device} > /dev/null 2>&1
+mount -o noatime /dev/${device} ${tempdir}
+
+back=$PWD
+
+cd /var
+if [ -z "${VARMFS_COPYDBPKG:-}" ]; then
+ find . -not -path "*/db/pkg*" -print -depth | cpio -dump --quiet ${tempdir}
+else
+ find . -print -depth | cpio -dump --quiet ${tempdir}
+fi
+
+cd $back
+
+mtree -PUer -q -p ${tempdir} < /etc/mtree/var.dist > /dev/null 2>&1
+
+umount ${tempdir}
+mount -o noatime /dev/${device} /var
diff --git a/src/etc/rc.dhclient_cron b/src/etc/rc.dhclient_cron
new file mode 100755
index 0000000..a38932d
--- /dev/null
+++ b/src/etc/rc.dhclient_cron
@@ -0,0 +1,53 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.dhclient_cron
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2006 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+
+/* invalidate cache */
+vc_invalidate();
+
+unlink_if_exists("/tmp/config.cache");
+
+$iflist = get_configured_interface_with_descr();
+foreach ($iflist as $ifname => $interface) {
+ $real_interface = get_real_interface($ifname);
+ if ($config['interfaces'][$ifname]['ipaddr'] == "dhcp") {
+ $pid = find_dhclient_process($real_interface);
+ if ($pid == 0 or !$pid) {
+ /* dhclient is not running for interface, kick it */
+ log_error("DHCLIENT was not running for {$real_interface} ... Launching new instance.");
+ exec("/sbin/dhclient $real_interface");
+ }
+ }
+}
+
+?>
diff --git a/src/etc/rc.disable_hdd_apm b/src/etc/rc.disable_hdd_apm
new file mode 100755
index 0000000..e9b3ba5
--- /dev/null
+++ b/src/etc/rc.disable_hdd_apm
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+ATAIDLE=/usr/local/sbin/ataidle
+for i in /dev/ad?; do
+ if [ ! -e ${i} ]; then
+ continue;
+ fi
+ SUPPORTED=`${ATAIDLE} ${i} | grep "APM Supported" | awk '{print $3;}'`
+ if [ "${SUPPORTED}" = "yes" ] ; then
+ echo Disabling APM on $i
+ ${ATAIDLE} -P 0 ${i}
+ fi
+done
diff --git a/src/etc/rc.dumpon b/src/etc/rc.dumpon
new file mode 100755
index 0000000..1ad40bb
--- /dev/null
+++ b/src/etc/rc.dumpon
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Based on:
+# FreeBSD: src/etc/rc.d/dumpon,v 1.12.2.1.4.1 2010/06/14 02:09:06 kensmith Exp
+
+# dumpon
+
+dumpon_try()
+{
+ if /sbin/dumpon "${1}" ; then
+ # Make a symlink in devfs for savecore
+ echo "Using ${1} for dump device."
+ ln -fs "${1}" /dev/dumpdev
+ return 0
+ fi
+ echo "Unable to specify $1 as a dump device."
+ return 1
+}
+
+# Enable dumpdev so that savecore can see it. Enable it
+# early so a crash early in the boot process can be caught.
+#
+while read dev mp type more ; do
+ [ "${type}" = "swap" ] || continue
+ [ -c "${dev}" ] || continue
+ dumpon_try "${dev}" && works=true
+done </etc/fstab
+if [ "${works}" != "true" ]; then
+ echo "No suitable dump device was found." 1>&2
+ exit
+fi \ No newline at end of file
diff --git a/src/etc/rc.dyndns.update b/src/etc/rc.dyndns.update
new file mode 100755
index 0000000..543b5a0
--- /dev/null
+++ b/src/etc/rc.dyndns.update
@@ -0,0 +1,58 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.dyndns.update
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("gwlb.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+/* Interface IP address has changed */
+
+if (isset($_GET['dyndns'])) {
+ $argument = $_GET['dyndns'];
+} else {
+ $argument = trim($argv[1], " \n");
+}
+
+if (empty($argument) || $argument == "all") {
+ services_dyndns_configure();
+ services_dnsupdate_process();
+} else {
+ $interface = lookup_gateway_interface_by_name($argument);
+ if (empty($interface)) {
+ $interface = $argument;
+ }
+ services_dyndns_configure($interface);
+ services_dnsupdate_process($interface);
+}
+
+?>
diff --git a/src/etc/rc.embedded b/src/etc/rc.embedded
new file mode 100755
index 0000000..663822d
--- /dev/null
+++ b/src/etc/rc.embedded
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# rc.embedded - embedded system specific startup information
+# For pfSense
+
+# Size of /tmp
+USE_MFS_TMP_SIZE=`/usr/bin/grep use_mfs_tmp_size /cf/conf/config.xml | /usr/bin/cut -f2 -d'>' | /usr/bin/cut -f1 -d'<'`
+if [ ! -z ${USE_MFS_TMP_SIZE} ] && [ ${USE_MFS_TMP_SIZE} -gt 0 ]; then
+ tmpsize="${USE_MFS_TMP_SIZE}m"
+else
+ tmpsize="40m"
+fi
+
+# Size of /var
+USE_MFS_VAR_SIZE=`/usr/bin/grep use_mfs_var_size /cf/conf/config.xml | /usr/bin/cut -f2 -d'>' | /usr/bin/cut -f1 -d'<'`
+if [ ! -z ${USE_MFS_VAR_SIZE} ] && [ ${USE_MFS_VAR_SIZE} -gt 0 ]; then
+ varsize="${USE_MFS_VAR_SIZE}m"
+else
+ varsize="60m"
+fi
+
+echo -n "Setting up memory disks..."
+mdmfs -S -M -s ${tmpsize} md /tmp
+mdmfs -S -M -s ${varsize} md /var
+
+# Create some needed directories
+/bin/mkdir -p /var/db /var/spool/lock
+/usr/sbin/chown uucp:dialer /var/spool/lock
+
+# Ensure vi's recover directory is present
+/bin/mkdir -p /var/tmp/vi.recover/
+echo " done."
diff --git a/src/etc/rc.expireaccounts b/src/etc/rc.expireaccounts
new file mode 100755
index 0000000..3befa17
--- /dev/null
+++ b/src/etc/rc.expireaccounts
@@ -0,0 +1,70 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.expireaccounts
+ part of pfSense
+
+ Copyright (C) 2009 Shrew Soft Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ require_once("config.inc");
+ require_once("functions.inc");
+
+ $removed = 0;
+ if (!is_array($config['system']['user'])) {
+ return;
+ }
+
+ $count = count($config['system']['user']);
+ $index = 0;
+ for (; $index < $count; $index++) {
+ $user =& $config['system']['user'][$index];
+ if ($user['scope'] == "system") {
+ continue;
+ }
+ echo "1\n";
+ echo "User {$user['name']} expires {$user['expires']}\n";
+ if (!$user['expires'] || isset($user['disabled'])) {
+ continue;
+ }
+ echo "1\n";
+ if (strtotime("-1 day") > strtotime($user['expires'])) {
+ echo "Disabling user {$user['name']} at index #{$index}\n";
+ //unset($config['system']['user'][$index]);
+ $user['disabled'] = true;
+ $removed++;
+ $count--;
+ $index--;
+ }
+ }
+
+ if ($removed > 0) {
+ write_config("Expired {$removed} user accounts");
+ }
+
+ //print_r($config);
+
+?>
diff --git a/src/etc/rc.filter_configure b/src/etc/rc.filter_configure
new file mode 100755
index 0000000..2c996e9
--- /dev/null
+++ b/src/etc/rc.filter_configure
@@ -0,0 +1,43 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.filter_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+/* invalidate interface cache */
+get_interface_arr(true);
+
+unlink_if_exists("/tmp/config.cache");
+filter_configure();
+
+?>
diff --git a/src/etc/rc.filter_configure_sync b/src/etc/rc.filter_configure_sync
new file mode 100755
index 0000000..86ab309
--- /dev/null
+++ b/src/etc/rc.filter_configure_sync
@@ -0,0 +1,41 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.filter_configure_sync
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+
+filter_configure_sync();
+
+?>
diff --git a/src/etc/rc.filter_configure_xmlrpc b/src/etc/rc.filter_configure_xmlrpc
new file mode 100755
index 0000000..584cc9c
--- /dev/null
+++ b/src/etc/rc.filter_configure_xmlrpc
@@ -0,0 +1,53 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.filter_configure_xmlrpc
+ Copyright (C) 2004-2006 Scott Ullrich
+ Copyright (C) 2005 Bill Marquette
+ Copyright (C) 2006 Peter Allgeyer
+ Copyright (C) 2008 Ermal Luçi
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("xmlrpc.inc");
+require_once("interfaces.inc");
+
+system_routing_configure();
+setup_gateways_monitor();
+relayd_configure();
+require_once("openvpn.inc");
+openvpn_resync_all();
+services_dhcpd_configure();
+
+?>
diff --git a/src/etc/rc.filter_synchronize b/src/etc/rc.filter_synchronize
new file mode 100755
index 0000000..f31fa34
--- /dev/null
+++ b/src/etc/rc.filter_synchronize
@@ -0,0 +1,488 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.filter_synchronize
+ Copyright (C) 2004-2006 Scott Ullrich
+ Copyright (C) 2005 Bill Marquette
+ Copyright (C) 2006 Peter Allgeyer
+ Copyright (C) 2008 Ermal Luçi
+ All rights reserved.
+
+ originally part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("xmlrpc.inc");
+require_once("interfaces.inc");
+
+/*
+ * backup_vip_config_section($section): returns as an xml file string of
+ * the configuration section
+ */
+function backup_vip_config_section() {
+ global $config;
+
+ if (!is_array($config['virtualip']['vip'])) {
+ return;
+ }
+ $temp = array();
+ $temp['vip'] = array();
+ foreach ($config['virtualip']['vip'] as $section) {
+ if (($section['mode'] == 'proxyarp' || $section['mode'] == 'ipalias') &&
+ (strpos($section['interface'], '_vip') === FALSE) &&
+ (strpos($section['interface'], 'lo0') === FALSE)) {
+ continue;
+ }
+ if ($section['advskew'] <> "") {
+ $section_val = intval($section['advskew']);
+ $section_val=$section_val+100;
+ if ($section_val > 254) {
+ $section_val = 254;
+ }
+ $section['advskew'] = $section_val;
+ }
+ if ($section['advbase'] <> "") {
+ $section_val = intval($section['advbase']);
+ if ($section_val > 254) {
+ $section_val = 254;
+ }
+ $section['advbase'] = $section_val;
+ }
+ $temp['vip'][] = $section;
+ }
+ return $temp;
+}
+
+function remove_special_characters($string) {
+ $match_array = "";
+ preg_match_all("/[a-zA-Z0-9\_\-]+/", $string, $match_array);
+ $string = "";
+ foreach ($match_array[0] as $ma) {
+ if ($string <> "") {
+ $string .= " ";
+ }
+ $string .= $ma;
+ }
+ return $string;
+}
+
+function carp_check_version($url, $username, $password, $port = 80, $method = 'pfsense.host_firmware_version') {
+ global $config, $g;
+
+ if (file_exists("{$g['varrun_path']}/booting") || platform_booting()) {
+ return;
+ }
+
+ $params = array(
+ XML_RPC_encode($password)
+ );
+
+ $numberofruns = 0;
+ while ($numberofruns < 2) {
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ if ($numberofruns > 0) {
+ $cli->setDebug(1);
+ }
+ /* send our XMLRPC message and timeout after 240 seconds */
+ $resp = $cli->send($msg, "240");
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting XMLRPC sync with username {$username} {$url}:{$port}.";
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting XMLRPC sync with username {$username} {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ } else {
+ $parsed_response = XML_RPC_decode($resp->value());
+ if (!is_array($parsed_response)) {
+ if (trim($parsed_response) == "Authentication failed") {
+ $error = "An authentication failure occurred while trying to access {$url}:{$port} ({$method}).";
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ return false;
+ }
+ } else {
+ if (!isset($parsed_response['config_version']) ||
+ ($parsed_response['config_version'] < $config['version']) ||
+ ($parsed_response['config_version'] > $config['version'])) {
+ update_filter_reload_status("The other member is on a different configuration version of {$g['product_name']}. Sync will not be done to prevent problems!");
+ log_error("The other member is on a different configuration version of {$g['product_name']}. Sync will not be done to prevent problems!");
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ $numberofruns++;
+ }
+
+ return false;
+}
+
+function carp_sync_xml($url, $username, $password, $sections, $port = 80, $method = 'pfsense.restore_config_section') {
+ global $config, $g;
+
+ if (file_exists("{$g['varrun_path']}/booting") || platform_booting()) {
+ return;
+ }
+
+ update_filter_reload_status("Syncing CARP data to {$url}");
+
+ /* make a copy of config */
+ $config_copy = $config;
+
+ /* strip out nosync items */
+ if (is_array($config_copy['nat']['outbound']['rule'])) {
+ $rulescnt = count($config_copy['nat']['outbound']['rule']);
+ for ($x = 0; $x < $rulescnt; $x++) {
+ $config_copy['nat']['outbound']['rule'][$x]['descr'] = remove_special_characters($config_copy['nat']['outbound']['rule'][$x]['descr']);
+ if (isset ($config_copy['nat']['outbound']['rule'][$x]['nosync'])) {
+ unset ($config_copy['nat']['outbound']['rule'][$x]);
+ }
+ }
+ }
+ if (is_array($config_copy['nat']['rule'])) {
+ $natcnt = count($config_copy['nat']['rule']);
+ for ($x = 0; $x < $natcnt; $x++) {
+ $config_copy['nat']['rule'][$x]['descr'] = remove_special_characters($config_copy['nat']['rule'][$x]['descr']);
+ if (isset ($config_copy['nat']['rule'][$x]['nosync'])) {
+ unset ($config_copy['nat']['rule'][$x]);
+ }
+ }
+ }
+ if (is_array($config_copy['filter']['rule'])) {
+ $filtercnt = count($config_copy['filter']['rule']);
+ for ($x = 0; $x < $filtercnt; $x++) {
+ $config_copy['filter']['rule'][$x]['descr'] = remove_special_characters($config_copy['filter']['rule'][$x]['descr']);
+ if (isset ($config_copy['filter']['rule'][$x]['nosync'])) {
+ unset ($config_copy['filter']['rule'][$x]);
+ }
+ }
+ }
+ if (is_array($config_copy['aliases']['alias'])) {
+ $aliascnt = count($config_copy['aliases']['alias']);
+ for ($x = 0; $x < $aliascnt; $x++) {
+ $config_copy['aliases']['alias'][$x]['descr'] = remove_special_characters($config_copy['aliases']['alias'][$x]['descr']);
+ if (isset ($config_copy['aliases']['alias'][$x]['nosync'])) {
+ unset ($config_copy['aliases']['alias'][$x]);
+ }
+ }
+ }
+ if (is_array($config_copy['dnsmasq']['hosts'])) {
+ $dnscnt = count($config_copy['dnsmasq']['hosts']);
+ for ($x = 0; $x < $dnscnt; $x++) {
+ $config_copy['dnsmasq']['hosts'][$x]['descr'] = remove_special_characters($config_copy['dnsmasq']['hosts'][$x]['descr']);
+ if (isset ($config_copy['dnsmasq']['hosts'][$x]['nosync'])) {
+ unset ($config_copy['dnsmasq']['hosts'][$x]);
+ }
+ }
+ }
+ if (is_array($config_copy['ipsec']['tunnel'])) {
+ $ipseccnt = count($config_copy['ipsec']['tunnel']);
+ for ($x = 0; $x < $ipseccnt; $x++) {
+ $config_copy['ipsec']['tunnel'][$x]['descr'] = remove_special_characters($config_copy['ipsec']['tunnel'][$x]['descr']);
+ if (isset ($config_copy['ipsec']['tunnel'][$x]['nosync'])) {
+ unset ($config_copy['ipsec']['tunnel'][$x]);
+ }
+ }
+ }
+
+ if (is_array($config_copy['dhcpd'])) {
+ foreach ($config_copy['dhcpd'] as $dhcpif => $dhcpifconf) {
+ if ($dhcpifconf['failover_peerip'] <> "") {
+ $int = guess_interface_from_ip($dhcpifconf['failover_peerip']);
+ $intip = find_interface_ip($int);
+ $config_copy['dhcpd'][$dhcpif]['failover_peerip'] = $intip;
+ }
+ }
+ }
+
+ foreach ($sections as $section) {
+ /* we can't use array_intersect_key()
+ * due to the vip 'special case'
+ */
+ switch ($section) {
+ case 'virtualip':
+ $xml[$section] = backup_vip_config_section();
+ break;
+ case 'user':
+ $xml['system'][$section] = $config_copy['system'][$section];
+ $xml['system']['nextuid'] = $config_copy['system']['nextuid'];
+ break;
+ case 'group':
+ $xml['system'][$section] = $config_copy['system'][$section];
+ $xml['system']['nextgid'] = $config_copy['system']['nextgid'];
+ break;
+ case 'authserver':
+ $xml['system'][$section] = $config_copy['system'][$section];
+ default:
+ $xml[$section] = $config_copy[$section];
+ }
+ }
+
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($xml)
+ );
+
+ $numberofruns = 0;
+ while ($numberofruns < 2) {
+ log_error("Beginning XMLRPC sync to {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ if ($numberofruns > 0) {
+ $cli->setDebug(1);
+ }
+ /* send our XMLRPC message and timeout after 240 seconds */
+ $resp = $cli->send($msg, "240");
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting XMLRPC sync with username {$username} {$url}:{$port}.";
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting XMLRPC sync with username {$username} {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ } else {
+ $parsed_response = XML_RPC_decode($resp->value());
+ if (!is_array($parsed_response) && trim($parsed_response) == "Authentication failed") {
+ $error = "An authentication failure occurred while trying to access {$url}:{$port} ($method).";
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ return -1;
+ } else {
+ log_error("XMLRPC sync successfully completed with {$url}:{$port}.");
+ update_filter_reload_status("XMLRPC sync successfully completed with {$url}:{$port}.");
+ }
+ $numberofruns = 3;
+ }
+ $numberofruns++;
+ }
+}
+
+if (platform_booting()) {
+ return;
+}
+
+if (is_array($config['hasync'])) {
+ update_filter_reload_status("Building high availability sync information");
+ $hasync = $config['hasync'];
+
+ if (empty($hasync['synchronizetoip'])) {
+ /* this gets hit on every filter sync on the secondary, a log here creates a lot of log spam and I never saw it actually log anything useful */
+ return;
+ }
+
+ /*
+ * XXX: The way we're finding the port right now is really suboptimal -
+ * we can't assume that the other machine is setup identically.
+ */
+ if (!empty($config['system']['webgui']['protocol'])) {
+ $synchronizetoip = $config['system']['webgui']['protocol'];
+ $synchronizetoip .= "://";
+ }
+
+ /* if port is empty lets rely on the protocol selection */
+ $port = $config['system']['webgui']['port'];
+ if (empty($port)) {
+ if ($config['system']['webgui']['protocol'] == "http") {
+ $port = "80";
+ } else {
+ $port = "443";
+ }
+ }
+
+ if (is_ipaddrv6($hasync['synchronizetoip'])) {
+ $hasync['synchronizetoip'] = "[{$hasync['synchronizetoip']}]";
+ }
+ $synchronizetoip .= $hasync['synchronizetoip'];
+ if ($hasync['synchronizerules'] != "") {
+ if (!is_array($config['filter'])) {
+ $config['filter'] = array();
+ }
+ $sections[] = 'filter';
+ }
+ if ($hasync['synchronizenat'] != "") {
+ if (!is_array($config['nat'])) {
+ $config['nat'] = array();
+ }
+ $sections[] = 'nat';
+ }
+ if ($hasync['synchronizealiases'] != "") {
+ if (!is_array($config['aliases'])) {
+ $config['aliases'] = array();
+ }
+ $sections[] = 'aliases';
+ }
+ if ($hasync['synchronizedhcpd'] != "" and is_array($config['dhcpd'])) {
+ $sections[] = 'dhcpd';
+ }
+ if ($hasync['synchronizewol'] != "") {
+ if (!is_array($config['wol'])) {
+ $config['wol'] = array();
+ }
+ $sections[] = 'wol';
+ }
+ if ($hasync['synchronizetrafficshaper'] != "" and is_array($config['shaper'])) {
+ $sections[] = 'shaper';
+ }
+ if ($hasync['synchronizetrafficshaperlimiter'] != "" and is_array($config['dnshaper'])) {
+ $sections[] = 'dnshaper';
+ }
+ if ($hasync['synchronizetrafficshaperlayer7'] != "" and is_array($config['l7shaper'])) {
+ $sections[] = 'l7shaper';
+ }
+ if ($hasync['synchronizestaticroutes'] != "") {
+ if (!is_array($config['staticroutes'])) {
+ $config['staticroutes'] = array();
+ }
+ if (!is_array($config['staticroutes']['route'])) {
+ $config['staticroutes']['route'] = array();
+ }
+ $sections[] = 'staticroutes';
+ if (!is_array($config['gateways'])) {
+ $config['gateways'] = array();
+ }
+ $sections[] = 'gateways';
+ }
+ if ($hasync['synchronizevirtualip'] != "") {
+ if (!is_array($config['virtualip'])) {
+ $config['virtualip'] = array();
+ }
+ $sections[] = 'virtualip';
+ }
+ if ($hasync['synchronizelb'] != "") {
+ if (!is_array($config['load_balancer'])) {
+ $config['load_balancer'] = array();
+ }
+ $sections[] = 'load_balancer';
+ }
+ if ($hasync['synchronizeipsec'] != "") {
+ if (!is_array($config['ipsec'])) {
+ $config['ipsec'] = array();
+ }
+ $sections[] = 'ipsec';
+ }
+ if ($hasync['synchronizeopenvpn'] != "") {
+ if (!is_array($config['openvpn'])) {
+ $config['openvpn'] = array();
+ }
+ $sections[] = 'openvpn';
+ }
+ if ($hasync['synchronizecerts'] != "" || $hasync['synchronizeopenvpn'] != "") {
+ if (!is_array($config['cert'])) {
+ $config['cert'] = array();
+ }
+ $sections[] = 'cert';
+
+ if (!is_array($config['ca'])) {
+ $config['ca'] = array();
+ }
+ $sections[] = 'ca';
+
+ if (!is_array($config['crl'])) {
+ $config['crl'] = array();
+ }
+ $sections[] = 'crl';
+ }
+ if ($hasync['synchronizeusers'] != "") {
+ $sections[] = 'user';
+ $sections[] = 'group';
+ }
+ if ($hasync['synchronizeauthservers'] != "") {
+ $sections[] = 'authserver';
+ }
+ if ($hasync['synchronizednsforwarder'] != "") {
+ if (is_array($config['dnsmasq'])) {
+ $sections[] = 'dnsmasq';
+ }
+ if (is_array($config['unbound'])) {
+ $sections[] = 'unbound';
+ }
+ }
+ if ($hasync['synchronizeschedules'] != "" || $hasync['synchronizerules'] != "") {
+ if (!is_array($config['schedules'])) {
+ $config['schedules'] = array();
+ }
+ $sections[] = 'schedules';
+ }
+ if ($hasync['synchronizecaptiveportal'] != "" and is_array($config['captiveportal'])) {
+ $sections[] = 'captiveportal';
+ }
+ if ($hasync['synchronizecaptiveportal'] != "" and is_array($config['vouchers'])) {
+ $sections[] = 'vouchers';
+ }
+
+ if (count($sections) <= 0) {
+ log_error("Nothing has been configured to be synched. Skipping....");
+ return;
+ }
+
+ if (empty($hasync['username'])) {
+ $username = "admin";
+ } else {
+ $username = $hasync['username'];
+ }
+
+ if (!carp_check_version($synchronizetoip, $username, $hasync['password'], $port)) {
+ return;
+ }
+
+ update_filter_reload_status("Signaling CARP reload signal...");
+ if (carp_sync_xml($synchronizetoip, $username, $hasync['password'], $sections, $port) == -1) {
+ return;
+ }
+ $cli = new XML_RPC_Client('/xmlrpc.php', $synchronizetoip, $port);
+ $params = array(
+ XML_RPC_encode($hasync['password'])
+ );
+
+ $msg = new XML_RPC_Message('pfsense.filter_configure', $params);
+ $cli->setCredentials($username, $hasync['password']);
+ $resp = $cli->send($msg, "900");
+
+ if (!is_object($resp)) {
+ $error = "A communications error occurred while attempting Filter sync with username {$username} {$synchronizetoip}:{$port}.";
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ } elseif ($resp->faultCode()) {
+ $error = "An error code was received while attempting Filter sync with username {$username} {$synchronizetoip}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "Settings Sync", "");
+ } else {
+ log_error("Filter sync successfully completed with {$synchronizetoip}:{$port}.");
+ $numberofruns = 3;
+ }
+}
+
+?>
diff --git a/src/etc/rc.firmware b/src/etc/rc.firmware
new file mode 100755
index 0000000..e8d549f
--- /dev/null
+++ b/src/etc/rc.firmware
@@ -0,0 +1,476 @@
+#!/bin/sh
+
+# /etc/rc.firmware
+# originally part of m0n0wall (http://neon1.net/m0n0wall)
+# Copyright (C) 2005-2009 Scott Ullrich <sullrich@pfsense.org>.
+# Copyright (C) 2003 Manuel Kasper <mk@neon1.net>.
+# All rights reserved.
+
+# mount /cf
+/etc/rc.conf_mount_rw
+
+# Reset file(s)
+echo "" >/conf/upgrade_log.txt
+echo "" >/conf/firmware_update_misc_log.txt
+echo "" >/conf/fdisk_upgrade_log.txt
+
+exec 3>&2 2>>/conf/firmware_update_misc_log.txt
+
+export ACTION=$1
+export IMG=$2
+if [ $# -eq 3 ]; then
+ export CUSTOMIMG=$3
+fi
+
+file_notice() {
+ /usr/local/bin/php-cgi -q -d auto_prepend_file=config.inc <<ENDOFF
+ <?php
+ require_once("globals.inc");
+ require_once("functions.inc");
+ file_notice("$1", "$2", "$1", "");
+ ?>
+ENDOFF
+}
+
+output_env_to_log() {
+ date >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ ls -lah /dev/ >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ ls -lah $IMG >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ md5 $IMG >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ mount >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ top >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+}
+
+backup_chflags() {
+ TOPROCESS="bin lib libexec sbin usr"
+ for files in $TOPROCESS; do
+ /usr/sbin/mtree -Pcp /${files} | bzip2 -9 > /tmp/chflags.dist.${files}.bz2 2>> /conf/upgrade_log.txt
+ done
+}
+
+restore_chflags() {
+ TOPROCESS="bin lib libexec sbin usr"
+ for files in $TOPROCESS; do
+ cd / && /usr/bin/bzcat /tmp/chflags.dist.${files}.bz2 | /usr/sbin/mtree -P -p /${files} >> /conf/upgrade_log.txt 2>&1
+ done
+}
+
+remove_chflags() {
+ TOPROCESS="bin lib libexec sbin usr"
+ for files in $TOPROCESS; do
+ /bin/chflags -R noschg /${files}
+ /bin/chmod -R u+rw /${files}
+ done
+}
+
+case $ACTION in
+enable)
+ touch /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+ echo "Enable" >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+ /etc/rc.conf_mount_ro
+ ;;
+auto)
+ touch /var/run/firmwarelock.dirty
+ backup_chflags
+ remove_chflags
+ /etc/rc.firmware_auto
+ restore_chflags
+ /etc/rc.conf_mount_ro
+ ;;
+pfSenseNanoBSDupgrade)
+
+ # Sanity check - bail early if there's no firmware file!
+ if [ ! -r $IMG ]; then
+ echo "2nd parameter has not been passed or file does not exist. Exiting." >> /conf/upgrade_log.txt 2>&1
+ /etc/rc.conf_mount_ro
+ exit 1
+ fi
+
+ # Prevent full upgrade file from being used to upgrade
+ if [ `echo $IMG | grep "full"` ]; then
+ echo "You cannot use a full file for upgrade. Please use a file labelled nanobsd upgrade."
+ file_notice "NanoBSDUpgradeFailure" "You have attempted to use a full NanoBSD installation file as an upgrade. Please use a NanoBSD file labelled 'upgrade' instead."
+ rm -f $IMG
+ /etc/rc.conf_mount_ro
+ exit 1
+ fi
+
+ touch /var/run/firmwarelock.dirty
+
+ echo "NanoBSD Firmware upgrade in progress..." >> /conf/upgrade_log.txt 2>&1
+ echo "NanoBSD Firmware upgrade in progress..." | wall
+ /etc/rc.notify_message -e -g -m "NanoBSD Firmware upgrade in progress..."
+
+ # backup config
+ /bin/mkdir -p /tmp/configbak
+ cp -Rp /conf/* /tmp/configbak 2>/dev/null
+
+ # Remove logs from backup dir to avoid clobbering upon restore.
+ rm /tmp/configbak/*_log.txt 2>/dev/null
+
+ echo "" >> /conf/upgrade_log.txt
+
+ echo "Installing ${IMG}." >> /conf/upgrade_log.txt 2>&1
+ echo "Installing ${IMG}." | wall
+
+ # resolve glabel label that we booted from
+ BOOT_DEVICE=`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`
+ # resolve glabel to the real boot dev entry
+ REAL_BOOT_DEVICE=`/sbin/glabel list | /usr/bin/grep -B2 ufs/${BOOT_DEVICE} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`
+ # grab the boot device, example ad1, ad0
+ BOOT_DRIVE=`/sbin/glabel list | /usr/bin/grep -B2 ufs/pfsense | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' ' | /usr/bin/cut -d's' -f1`
+ # test the slice. if we are on slice 1 we need to flash 2 and vice versa
+ if [ `echo $REAL_BOOT_DEVICE | /usr/bin/grep "s1"` ]; then
+ SLICE="2"
+ OLDSLICE="1"
+ TOFLASH="${BOOT_DRIVE}s${SLICE}"
+ COMPLETE_PATH="${BOOT_DRIVE}s${SLICE}a"
+ GLABEL_SLICE="pfsense1"
+ UFS_ID="1"
+ OLD_UFS_ID="0"
+ else
+ SLICE="1"
+ OLDSLICE="2"
+ TOFLASH="${BOOT_DRIVE}s${SLICE}"
+ COMPLETE_PATH="${BOOT_DRIVE}s${SLICE}a"
+ GLABEL_SLICE="pfsense0"
+ UFS_ID="0"
+ OLD_UFS_ID="1"
+ fi
+
+ # Output specific information that this script is using
+ echo "SLICE ${SLICE}" >> /conf/upgrade_log.txt
+ echo "OLDSLICE ${OLDSLICE}" >> /conf/upgrade_log.txt
+ echo "TOFLASH ${TOFLASH}" >> /conf/upgrade_log.txt
+ echo "COMPLETE_PATH ${COMPLETE_PATH}" >> /conf/upgrade_log.txt
+ echo "GLABEL_SLICE ${GLABEL_SLICE}" >> /conf/upgrade_log.txt
+
+ # First ensure the new file can fit inside the
+ # slice that we are going to be operating on.
+ NEW_IMG_SIZE=`echo $((\`gzip -l ${IMG} | grep -v compressed | awk '{ print $2}'\` / 1024 / 1024))`
+ SIZE=`/sbin/fdisk ${COMPLETE_PATH} | /usr/bin/grep Meg | /usr/bin/awk '{ print $5 }' | /usr/bin/cut -d"(" -f2`
+ # USB slices are under-reported even more than CF slices when viewed
+ # directly, instead of when looking at the entire disk. Compensate
+ # by adding exactly 6MB. 4MB was consistently 2MB too few, and
+ # was resulting in failing upgrades on USB Flash based installs.
+ SIZE=`expr $SIZE + 6`
+ if [ "$SIZE" -lt "$NEW_IMG_SIZE" ]; then
+ file_notice "UpgradeFailure" "Upgrade failed due to the upgrade image being larger than the partition that is configured on disk. Halting. Size on disk: $SIZE < Size of new image: $NEW_IMG_SIZE"
+ echo "Upgrade failed. Please check the system log file for more information" | wall
+ rm -f $IMG
+ rm -f /var/run/firmwarelock.dirty
+ rm -f /var/run/firmware.lock
+ rm -f ${IMG}
+ /etc/rc.conf_mount_ro
+ exit 1
+ fi
+
+ # Output environment information to log file
+ output_env_to_log
+
+ # Grab a before upgrade look at fdisk
+ echo "" >> /conf/fdisk_upgrade_log.txt
+ echo "Before upgrade fdisk/bsdlabel" >> /conf/fdisk_upgrade_log.txt
+ fdisk $BOOT_DRIVE >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s1 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s2 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s3 >> /conf/fdisk_upgrade_log.txt
+ echo "---------------------------------------------------------------" >> /conf/fdisk_upgrade_log.txt
+ echo "" >> /conf/fdisk_upgrade_log.txt
+
+ # Log that we are really doing a NanoBSD upgrade
+ echo "" >> /conf/upgrade_log.txt
+ echo "NanoBSD upgrade starting" >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ # Remove TOFLASH and get ready for new flash image
+ echo "" >> /conf/upgrade_log.txt
+ echo "dd if=/dev/zero of=/dev/${TOFLASH} bs=1m count=1" >> /conf/upgrade_log.txt
+ dd if=/dev/zero of=/dev/${TOFLASH} bs=1m count=1 >> /conf/upgrade_log.txt 2>&1
+
+ # Stream gzipped image to dd and explode image to new area
+ echo "" >> /conf/upgrade_log.txt
+ echo "/usr/bin/gzip -dc $IMG | /bin/dd of=/dev/${TOFLASH} obs=64k" >> /conf/upgrade_log.txt
+ /usr/bin/gzip -dc $IMG | /bin/dd of=/dev/${TOFLASH} obs=64k >> /conf/upgrade_log.txt 2>&1
+
+ # Grab an after upgrade look at fdisk
+ echo "" >> /conf/fdisk_upgrade_log.txt
+ echo "After upgrade fdisk/bsdlabel" >> /conf/upgrade_log.txt
+ fdisk $BOOT_DRIVE >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s1 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s2 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s3 >> /conf/fdisk_upgrade_log.txt
+ echo "---------------------------------------------------------------" >> /conf/fdisk_upgrade_log.txt
+ echo "" >> /conf/fdisk_upgrade_log.txt
+
+ # Ensure that our new system is sound and bail if it is not and file a notice
+ echo "" >> /conf/upgrade_log.txt
+ echo "/sbin/fsck_ufs -y /dev/${COMPLETE_PATH}" >> /conf/upgrade_log.txt
+ /sbin/fsck_ufs -y /dev/${COMPLETE_PATH} >> /conf/upgrade_log.txt 2>&1
+ if [ $? != 0 ]; then
+ file_notice "UpgradeFailure" "{\$g['product_name']} upgrade has failed. Your system has been left in a usable state."
+ rm -f $IMG
+ rm -f /var/run/firmwarelock.dirty
+ rm -f /var/run/firmware.lock
+ /etc/rc.conf_mount_ro
+ exit 1
+ fi
+
+ # Enable foot shooting
+ sysctl kern.geom.debugflags=16
+
+ # Add back the corresponding glabel
+ echo "" >> /conf/upgrade_log.txt
+ echo "/sbin/tunefs -L ${GLABEL_SLICE} /dev/${COMPLETE_PATH}" >> /conf/upgrade_log.txt
+ /sbin/tunefs -L ${GLABEL_SLICE} /dev/${COMPLETE_PATH} >> /conf/upgrade_log.txt 2>&1
+
+ # restore config
+ cp -Rp /tmp/configbak/* /conf 2>/dev/null
+
+ # Remove upgrade file
+ rm -f $IMG
+
+ # Mount newly prepared slice
+ mkdir /tmp/$GLABEL_SLICE
+ mount /dev/ufs/$GLABEL_SLICE /tmp/$GLABEL_SLICE
+
+ # If /boot/loader.conf.local exists
+ # copy to the other slice.
+ if [ -f /boot/loader.conf.local ]; then
+ cp /boot/loader.conf.local /tmp/$GLABEL_SLICE/boot/loader.conf.local
+ fi
+
+ # If /tmp/$GLABEL_SLICE/usr/local/share/pfSense/post_upgrade_command exists
+ # after update then execute the command.
+ echo "Checking for post_upgrade_command..." >> /conf/upgrade_log.txt
+ if [ -f /tmp/$GLABEL_SLICE/usr/local/share/pfSense/post_upgrade_command ]; then
+ echo "Found post_upgrade_command, executing ($GLABEL_SLICE)..." >> /conf/upgrade_log.txt
+ sh /tmp/$GLABEL_SLICE/usr/local/share/pfSense/post_upgrade_command $GLABEL_SLICE >> /conf/upgrade_log.txt 2>&1
+ fi
+
+ # Update fstab
+ cp /etc/fstab /tmp/$GLABEL_SLICE/etc/fstab
+ sed -i "" "s/pfsense${OLD_UFS_ID}/pfsense${UFS_ID}/g" /tmp/$GLABEL_SLICE/etc/fstab
+ if [ $? != 0 ]; then
+ echo "Something went wrong when trying to update the fstab entry. Aborting upgrade."
+ file_notice "UpgradeFailure" "Something went wrong when trying to update the fstab entry. Aborting upgrade."
+ rm -f $IMG
+ rm -f /var/run/firmwarelock.dirty
+ rm -f /var/run/firmware.lock
+ umount /tmp/$GLABEL_SLICE
+ /etc/rc.conf_mount_ro
+ exit 1
+ fi
+ echo "" >> /conf/upgrade_log.txt
+ cat /tmp/$GLABEL_SLICE/etc/fstab >> /conf/upgrade_log.txt
+
+ echo "" >> /conf/upgrade_log.txt
+ find /tmp/$GLABEL_SLICE >/conf/file_upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ # Unmount newly prepared slice
+ umount /tmp/$GLABEL_SLICE
+
+ sync
+
+ # Set active mount slice in fdisk
+ echo "" >> /conf/upgrade_log.txt
+ echo "gpart set -a active -i ${SLICE} ${BOOT_DRIVE}" >> /conf/upgrade_log.txt
+ gpart set -a active -i ${SLICE} ${BOOT_DRIVE} >> /conf/upgrade_log.txt 2>&1
+
+ sync
+
+ # Set active boot source - NanoBSD does not do this but otherwise we
+ # end up with the wrong partition being active.
+ echo "" >> /conf/upgrade_log.txt
+ echo "/usr/sbin/boot0cfg -s ${SLICE} -v /dev/${BOOT_DRIVE}" >> /conf/upgrade_log.txt
+ /usr/sbin/boot0cfg -s ${SLICE} -v /dev/${BOOT_DRIVE} >> /conf/upgrade_log.txt 2>&1
+
+ # Disable foot shooting
+ sysctl kern.geom.debugflags=0
+
+ # Grab a final look at fdisk
+ echo "" >> /conf/fdisk_upgrade_log.txt
+ echo "Final upgrade fdisk/bsdlabel" >> /conf/fdisk_upgrade_log.txt
+ fdisk $BOOT_DRIVE >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s1 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s2 >> /conf/fdisk_upgrade_log.txt
+ bsdlabel -A ${BOOT_DRIVE}s3 >> /conf/fdisk_upgrade_log.txt
+ echo "---------------------------------------------------------------" >> /conf/fdisk_upgrade_log.txt
+ echo "" >> /conf/fdisk_upgrade_log.txt
+
+ # Remove extra stuff
+ rm -rf /usr/savecore/*
+
+ date >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ # Trigger a package reinstallation on reboot
+ touch /conf/needs_package_sync
+
+ # remount /cf ro
+ /etc/rc.conf_mount_ro
+ /bin/sync
+
+ echo "NanoBSD Firmware upgrade is complete. Rebooting in 10 seconds." >> /conf/upgrade_log.txt 2>&1
+ echo "NanoBSD Firmware upgrade is complete. Rebooting in 10 seconds." | wall
+ /etc/rc.notify_message -e -g -m "NanoBSD Firmware upgrade is complete. Rebooting in 10 seconds."
+
+ sleep 10
+
+ rm -f /var/run/firmwarelock.dirty
+ rm -f /var/run/firmware.lock
+ . /etc/rc.reboot
+
+ ;;
+pfSenseupgrade)
+
+ # Sanity check - bail early if there's no firmware file!
+ if [ ! -r $IMG ]; then
+ echo "2nd parameter has not been passed or file does not exist. Exiting." >> /conf/upgrade_log.txt 2>&1
+ /etc/rc.conf_mount_ro
+ exit
+ fi
+
+ # wait 1 second before beginning
+ sleep 1
+
+ # Log that we are really doing a pfSense upgrade
+ echo "" >> /conf/upgrade_log.txt
+ echo "pfSenseupgrade upgrade starting" >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ touch /var/run/firmwarelock.dirty
+
+ if [ -f /tmp/perform_full_backup.txt ]; then
+ echo "Performing full backup" >> /conf/upgrade_log.txt
+ /etc/rc.create_full_backup
+ rm /tmp/perform_full_backup.txt
+ fi
+
+ touch /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ # Output environment information to log file
+ output_env_to_log
+
+ backup_chflags
+ remove_chflags
+
+ # Do we have a pre-upgrade hook in the update file?
+ if [ `tar tvzf $IMG | grep /usr/local/share/pfSense/pre_upgrade_command | wc -l` -gt 0 ]; then
+ tar xzvf $IMG -C / ./usr/local/share/pfSense/pre_upgrade_command >> /conf/upgrade_log.txt 2>&1
+ chmod a+rx /usr/local/share/pfSense/pre_upgrade_command >> /conf/upgrade_log.txt 2>&1
+ sh /usr/local/share/pfSense/pre_upgrade_command >> /conf/upgrade_log.txt 2>&1
+ fi
+
+ echo "Firmware upgrade in progress..." >> /conf/upgrade_log.txt 2>&1
+ echo "Firmware upgrade in progress..." | wall
+ /etc/rc.notify_message -e -g -m "Firmware upgrade in progress..."
+
+ # backup config
+ [ -d /tmp/configbak ] && rm -rf /tmp/configbak
+ /bin/mkdir -p /tmp/configbak
+ cp -Rp /conf/* /tmp/configbak 2>/dev/null
+
+ # Remove logs from backup dir to avoid clobbering upon restore.
+ rm /tmp/configbak/*_log.txt 2>/dev/null
+
+ # tar explode image onto hd
+ killall -9 check_reload_status
+ killall -9 check_reload_status
+ echo "Installing $IMG." >> /conf/upgrade_log.txt 2>&1
+ cd / && /usr/bin/tar --exclude=./dev -xzUPf $IMG >> /conf/upgrade_log.txt 2>&1
+ /usr/local/sbin/check_reload_status
+ echo "Image installed $IMG." >> /conf/upgrade_log.txt 2>&1
+
+ # process custom image if its passed
+ if [ $# -eq 3 ]; then
+ if [ -f $CUSTOMIMG ]; then
+ echo "Custom image $CUSTOMIMG found." >> /conf/upgrade_log.txt 2>&1
+ echo "Custom image ($CUSTOMIMG) found." >> /conf/upgrade_log.txt 2>&1
+ PWD_DIR=`pwd`
+ cd / && /usr/bin/tar xzPUf $CUSTOMIMG >> /conf/upgrade_log.txt 2>&1
+ cd $PWD_DIR
+ echo "Custom image $CUSTOMIMG installed." >> /conf/upgrade_log.txt 2>&1
+ fi
+ fi
+
+ # restore config
+ cp -Rp /tmp/configbak/* /conf 2>/dev/null
+
+ # restore /etc symlinks
+ rm /etc/hosts
+ ln -s /var/etc/hosts /etc/hosts
+
+ restore_chflags
+
+ # Remove upgrade file
+ rm -f $IMG
+
+ if [ -e /etc/init_bootloader.sh ]; then
+ if [ ! -x /etc/init_bootloader.sh ]; then
+ chmod ug+x /etc/init_bootloader.sh
+ fi
+ /etc/init_bootloader.sh >> /conf/upgrade_log.txt 2>&1
+ fi
+
+ # Remove saved commit ID for gitsync
+ rm -f /etc/version.gitsync
+
+ # If /usr/local/share/pfSense/post_upgrade_command exists after update
+ # then execute the command.
+ if [ -f /usr/local/share/pfSense/post_upgrade_command ]; then
+ if [ ! -x /usr/local/share/pfSense/post_upgrade_command ]; then
+ chmod ug+x /usr/local/share/pfSense/post_upgrade_command
+ fi
+ /usr/local/share/pfSense/post_upgrade_command >> /conf/upgrade_log.txt 2>&1
+ fi
+
+ # remove unused files
+ rm -rf /etc/rc.conf
+ rm -rf /usr/savecore/*
+
+ date >> /conf/upgrade_log.txt
+ echo "" >> /conf/upgrade_log.txt
+
+ # remount /cf ro
+ /etc/rc.conf_mount_ro
+
+ # release the firmware lock
+ rm -f /var/run/firmwarelock.dirty
+ rm -f /var/run/firmware.lock
+ /bin/sync
+
+ echo "Firmware upgrade is complete. Rebooting in 10 seconds." >> /conf/upgrade_log.txt 2>&1
+ echo "Firmware upgrade is complete. Rebooting in 10 seconds." | wall
+ /etc/rc.notify_message -e -g -m "Firmware upgrade is complete. Rebooting in 10 seconds."
+
+ # Sleep and allow disks to catch up
+ sleep 10
+
+ # If the archive has unpacked a file called
+ # /tmp/no_upgrade_reboot_required then do
+ # not reboot after upgrade.
+ if [ -f /tmp/no_upgrade_reboot_required ]; then
+ rm /tmp/no_upgrade_reboot_required
+ else
+ . /etc/rc.reboot
+ fi
+
+ ;;
+esac
+
diff --git a/src/etc/rc.firmware_auto b/src/etc/rc.firmware_auto
new file mode 100755
index 0000000..5b355df
--- /dev/null
+++ b/src/etc/rc.firmware_auto
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# /etc/rc.firmware_auto
+# Copyright (C) 2005-2015 Electric Sheep Fencing LLC
+# Part of pfSense
+
+# $Id$
+
+FMBASEURL=$1
+FMFILENAME=$2
+FETCHFILENAME=$1/$2
+
+product=`cat /etc/inc/globals.inc | grep product_name | cut -d'"' -f4`
+
+# wait 5 seconds before beginning
+sleep 5
+
+logger -p daemon.info -i -t AutoUpgrade "Auto Upgrade started"
+
+HTTP_AUTH=""
+
+# if username and password is passed, let fetch utilize.
+if [ $# -gt 3 ]; then
+HTTP_AUTH="basic:*:$3:$4"
+fi
+
+if [ $# -gt 1 ]; then
+ echo "Downloading $FMFILENAME from $FMBASEURL ..." | logger -p daemon.info -i -t AutoUpgrade
+ /usr/bin/fetch -o /tmp/latest.tgz $FETCHFILENAME | logger -p daemon.info -i -t AutoUpgrade
+ echo "Downloading $FMFILENAME.sha256 from $FMBASEURL ..." | logger -p daemon.info -i -t AutoUpgrade
+ /usr/bin/fetch -o /tmp/latest.tgz.sha256 $FETCHFILENAME.sha256 | logger -p daemon.info -i -t AutoUpgrade
+fi
+
+DLHASH=`/bin/cat /tmp/latest.tgz.sha256 | cut -d" " -f4 `
+FILEHASH=`/sbin/sha256 /tmp/latest.tgz | cut -d" " -f4`
+
+PLATFORM=`cat /etc/platform`
+
+echo " Package sha256: ${DLHASH}" | logger -p daemon.info -i -t AutoUpgrade
+echo "Downloaded sha256: ${FILEHASH}" | logger -p daemon.info -i -t AutoUpgrade
+
+if [ "$DLHASH" = "" ]; then
+ echo "Downloaded sha256 is null. Require proxy auth?" | logger -p daemon.info -i -t AutoUpgrade
+ exit 1
+fi
+
+if [ "$FILEHASH" = "" ]; then
+ echo "Downloaded file's sha256 is null." | logger -p daemon.info -i -t AutoUpgrade
+ exit 1
+fi
+
+if [ "$DLHASH" = "$FILEHASH" ]; then
+ echo "sha256 hashes match." | logger -p daemon.info -i -t AutoUpgrade
+ echo "Beginning ${product} upgrade." | wall
+ if [ "$PLATFORM" = "nanobsd" ]; then
+ /usr/local/bin/php-cgi /etc/rc.conf_mount_rw
+ fi
+ if [ -r "/tmp/custom.tgz" ]; then
+ sh /etc/rc.firmware pfSenseupgrade /tmp/latest.tgz /tmp/custom.tgz
+ else
+ if [ "$PLATFORM" = "nanobsd" ]; then
+ sh /etc/rc.firmware pfSenseNanoBSDupgrade /tmp/latest.tgz
+ else
+ sh /etc/rc.firmware pfSenseupgrade /tmp/latest.tgz
+ fi
+ fi
+ exit 0
+fi
+
+echo "sha256 hashes do not match. Upgrade aborted." | logger -p daemon.info -i -t AutoUpgrade
+rm /tmp/latest*
+exit 1
diff --git a/src/etc/rc.halt b/src/etc/rc.halt
new file mode 100755
index 0000000..fd6318b
--- /dev/null
+++ b/src/etc/rc.halt
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# $Id$
+
+if ! /usr/bin/lockf -s -t 30 /tmp/config.lock /usr/bin/true; then
+ echo "Cannot halt at this moment, a config write operation is in progress and 30 seconds have passed."
+ exit -1
+fi
+
+sleep 1
+
+/sbin/shutdown -p now
+
diff --git a/src/etc/rc.initial b/src/etc/rc.initial
new file mode 100755
index 0000000..b103bf7
--- /dev/null
+++ b/src/etc/rc.initial
@@ -0,0 +1,167 @@
+#!/bin/sh
+
+# /etc/rc.initial
+# part of pfSense by Scott Ullrich
+# Copyright (C) 2004-2011 Scott Ullrich, All rights reserved.
+# originally based on m0n0wall (http://neon1.net/m0n0wall)
+# Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+# All rights reserved.
+
+# make sure the user can't kill us by pressing Ctrl-C,
+# ctrl-z, etc.
+#trap : 2
+#trap : 3
+#trap : 4
+
+if [ -f /etc/rc.local ]; then
+ RCLOCALPWD=`ps awux | grep rc.local | grep -v grep | awk '{ print $2 }'`
+ if [ "$RCLOCALPWD" = "" ]; then
+ echo ">>> Launching rc.local in background..."
+ sh /etc/rc.local &
+ sleep 1
+ sh /etc/rc.local.running &
+ else
+ if [ -f /etc/rc.local.running ]; then
+ echo ">>> Launching rc.local.running in background..."
+ sh /etc/rc.local.running &
+ fi
+ fi
+fi
+
+CONFIG="/cf/conf/config.xml"
+WORD="https"
+
+# Set our operating platform
+PLATFORM=`cat /etc/platform`
+
+# endless loop
+while : ; do
+
+if [ -f /tmp/ttybug ]; then
+ rm /tmp/ttybug
+ exit && exit && logout
+fi
+
+/etc/rc.banner
+
+product=`grep product_name /etc/inc/globals.inc | cut -d'"' -f4`
+hidebanner=`grep hidebanner /etc/inc/globals.inc | cut -d'"' -f4`
+
+# Check to see if SSH is running.
+if pgrep -q -a -F /var/run/sshd.pid sshd >/dev/null 2>&1; then
+ sshd_option="14) Disable Secure Shell (sshd)";
+else
+ sshd_option="14) Enable Secure Shell (sshd)";
+fi
+
+for i in /var/db/pfi/capable_*; do
+ if [ -f $i -a ! -L /cf/conf ]; then
+ option98="98) Move configuration file to removable device"
+ break
+ fi
+done
+
+if [ "$PLATFORM" = "cdrom" ]; then
+ option99="99) Install ${product} to a hard drive, etc."
+fi
+
+# display a cheap menu
+echo ""
+echo " 0) Logout (SSH only) 9) pfTop"
+echo " 1) Assign Interfaces 10) Filter Logs"
+echo " 2) Set interface(s) IP address 11) Restart webConfigurator"
+echo " 3) Reset webConfigurator password 12) ${product} Developer Shell"
+echo " 4) Reset to factory defaults 13) Upgrade from console"
+echo " 5) Reboot system ${sshd_option}"
+echo " 6) Halt system 15) Restore recent configuration"
+echo " 7) Ping host 16) Restart PHP-FPM"
+echo " 8) Shell"
+echo " ${option98} "
+
+if [ "${option99}" != "" ]; then
+ /bin/echo "${option99}"
+fi
+
+echo
+read -p "Enter an option: " opmode
+echo
+
+# see what the user has chosen
+case ${opmode} in
+0)
+ exit && exit && logout
+ ;;
+1)
+ /etc/rc.initial.setports
+ ;;
+2)
+ /etc/rc.initial.setlanip
+ ;;
+3)
+ /etc/rc.initial.password
+ ;;
+4)
+ /etc/rc.initial.defaults
+ ;;
+5)
+ /etc/rc.initial.reboot
+ ;;
+6)
+ /etc/rc.initial.halt
+ ;;
+7)
+ /etc/rc.initial.ping
+ ;;
+8)
+ /bin/tcsh
+ ;;
+9)
+ /usr/local/sbin/pftop
+ ;;
+10)
+ /usr/local/sbin/clog -f /var/log/filter.log
+ ;;
+11 | 111)
+ /etc/rc.restart_webgui
+ ;;
+12)
+ /usr/local/sbin/pfSsh.php
+ ;;
+13)
+ php -f /etc/rc.initial.firmware_update
+ ;;
+14)
+ php -f /etc/rc.initial.toggle_sshd
+ ;;
+15)
+ /etc/rc.restore_config_backup
+ ;;
+16)
+ /etc/rc.php-fpm_restart
+ ;;
+98)
+ if [ ! -f /tmp/config_moved ]; then
+ /etc/rc.initial.store_config_to_removable_device
+ fi
+ ;;
+99)
+ if [ -e /dev/ukbd0 ]; then
+ env TERM=cons25 /scripts/lua_installer
+ else
+ /scripts/lua_installer
+ fi
+ ;;
+100)
+ if grep "$WORD" "$CONFIG"; then
+ links "https://localhost"
+ else
+ links "http://localhost"
+ fi
+ ;;
+"")
+ kill $PPID ; exit
+ ;;
+esac
+
+done
+
diff --git a/src/etc/rc.initial.defaults b/src/etc/rc.initial.defaults
new file mode 100755
index 0000000..6901dae
--- /dev/null
+++ b/src/etc/rc.initial.defaults
@@ -0,0 +1,62 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.defaults
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("util.inc");
+ require_once("config.lib.inc");
+ require_once("functions.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ echo <<<EOD
+
+You are about to reset the firewall to factory defaults.
+The firewall will reboot after resetting the configuration.
+
+Do you want to proceed [y|n]?
+EOD;
+
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+
+ reset_factory_defaults();
+
+ echo <<<EOD
+
+{$g['product_name']} is rebooting now.
+
+EOD;
+
+ system_reboot_sync();
+ }
+
+ fclose($fp);
+?>
diff --git a/src/etc/rc.initial.firmware_update b/src/etc/rc.initial.firmware_update
new file mode 100755
index 0000000..2dff066
--- /dev/null
+++ b/src/etc/rc.initial.firmware_update
@@ -0,0 +1,190 @@
+#!/usr/local/bin/php-cgi -f
+
+<?php
+
+require("globals.inc");
+require("config.inc");
+require("functions.inc");
+
+echo "Starting the {$g['product_name']} console firmware update system";
+
+require("functions.inc");
+echo ".";
+
+if (isset($config['system']['firmware']['alturl']['enable'])) {
+ $updater_url = "{$config['system']['firmware']['alturl']['firmwareurl']}";
+} else {
+ $updater_url = $g['update_url'];
+}
+
+$nanosize = "";
+if ($g['platform'] == "nanobsd") {
+ if (file_exists("/etc/nano_use_vga.txt")) {
+ $nanosize = "-nanobsd-vga-";
+ } else {
+ $nanosize = "-nanobsd-";
+ }
+
+ $nanosize .= strtolower(trim(file_get_contents("/etc/nanosize.txt")));
+ $update_filename = "latest{$nanosize}.img.gz";
+} else {
+ $update_filename = "latest.tgz";
+}
+$autoupdateurl = "{$updater_url}/{$update_filename}";
+
+$fp = fopen('php://stdin', 'r');
+
+echo ".\n\n";
+
+$shell_active = true;
+
+echo "1) Update from a URL\n";
+echo "2) Update from a local file\n";
+echo "Q) Quit\n";
+
+echo "\nPlease select an option to continue: ";
+
+$pkg_interface = 'console';
+$command = strtoupper(chop(fgets($fp)));
+
+switch ($command) {
+ case "q":
+ case "quit":
+ echo "\n";
+ fclose($fp);
+ die;
+ break;
+ case "1":
+ echo "\nEnter the URL to the .tgz or .img.gz update file. \nType 'auto' to use {$autoupdateurl}\n> ";
+ $url = chop(fgets($fp));
+ if (!$url) {
+ fclose($fp);
+ die;
+ }
+ if ($url == "auto") {
+ $url = $autoupdateurl;
+ }
+ $status = does_url_exist($url);
+ if ($status) {
+ conf_mount_rw();
+ mark_subsystem_dirty('firmware');
+ unlink_if_exists("/root/firmware.tgz");
+ echo "\nFetching file... ";
+ download_file_with_progress_bar($url, '/root/firmware.tgz');
+ if (!file_exists("/root/firmware.tgz")) {
+ echo "Something went wrong during file transfer. Exiting.\n\n";
+ fclose($fp);
+ clear_subsystem_dirty('firmware');
+ die;
+ }
+ $status = does_url_exist("$url.sha256");
+ if ($status) {
+ echo "\nFetching sha256... ";
+ download_file_with_progress_bar($url . ".sha256", '/root/firmware.tgz.sha256');
+ echo "\n";
+ } else {
+ echo "\n\nWARNING.\n";
+ echo "\nCould not locate a sha256 file. We cannot verify the download once completed.\n\n";
+ echo "Do you still want to proceed with the upgrade [n]? ";
+ $answer = strtoupper(chop(fgets($fp)));
+ if ($answer == "Y" or $answer == "YES") {
+ echo "\nContinuing upgrade...";
+ } else {
+ echo "\nUpgrade cancelled.\n\n";
+ die;
+ }
+ }
+ if (file_exists("/root/firmware.tgz.sha256")) {
+ $source_sha256 = trim(`cat /root/firmware.tgz.sha256 | awk '{ print \$4 }'`, "\r");
+ $file_sha256 = trim(`sha256 /root/firmware.tgz | awk '{ print \$4 }'`, "\r");
+ echo "URL sha256: $source_sha256\n";
+ echo "Downloaded file sha256: $file_sha256\n";
+ if ($source_sha256 <> $file_sha256) {
+ echo "\n\nsha256 checksum does not match. Cancelling upgrade.\n\n";
+ unlink_if_exists("/root/firmware.tgz.sha256");
+ fclose($fp);
+ clear_subsystem_dirty('firmware');
+ die -1;
+ }
+ echo "\nsha256 checksum matches.\n";
+ unlink_if_exists("/root/firmware.tgz.sha256");
+ }
+ if (strstr($url, "nanobsd")) {
+ echo "NanoBSD upgrade file detected...\n";
+ $type = "nanobsd";
+ } else {
+ $type = "normal";
+ }
+ do_upgrade("/root/firmware.tgz", $type);
+ clear_subsystem_dirty('firmware');
+ exit;
+ }
+ case "2":
+ echo "\nEnter the complete path to the .tgz or .img.gz update file: ";
+ $path = chop(fgets($fp));
+ if (!$path) {
+ fclose($fp);
+ die;
+ }
+ if (stristr($path, "nanobsd")) {
+ $type = "nanobsd";
+ }
+ if (file_exists($path)) {
+ mark_subsystem_dirty('firmware');
+ do_upgrade($path, $type);
+ clear_subsystem_dirty('firmware');
+ } else {
+ echo "\nCould not find file.\n\n";
+ fclose($fp);
+ die -1;
+ }
+}
+
+function do_upgrade($path, $type) {
+ global $g, $fp;
+
+ $sigchk = verify_digital_signature($path);
+ if ($sigchk == 1) {
+ $sig_warning = "The digital signature on this image is invalid.";
+ } elseif ($sigchk == 2) {
+ $sig_warning = "This image is not digitally signed.";
+ } elseif (($sigchk == 3) || ($sigchk == 4)) {
+ $sig_warning = "There has been an error verifying the signature on this image.";
+ }
+ if ($sig_warning) {
+ $sig_warning = "\nWARNING! ACHTUNG! DANGER!\n\n{$sig_warning}\n\n" .
+ "This means that the image you uploaded is not an official/supported image and\n" .
+ "may lead to unexpected behavior or security compromises.\n\n" .
+ "Only install images that come from sources that you trust, and make sure\n".
+ "that the image has not been tampered with.\n\n".
+ "Do you want to install this image anyway at your own risk [n]?";
+ echo $sig_warning;
+ $command = strtoupper(chop(fgets($fp)));
+ if (strtoupper($command) == "Y" or strtoupper($command) == "Y" or strtoupper($command) == "YES") {
+ echo "\nContinuing upgrade...";
+ } else {
+ echo "\nUpgrade cancelled.\n\n";
+ die;
+ }
+ }
+ mark_subsystem_dirty('firmwarelock');
+ echo "\nOne moment please...\nInvoking firmware upgrade...";
+ if ($type == "nanobsd") {
+ mwexec_bg("/etc/rc.firmware pfSenseNanoBSDupgrade $path");
+ } else {
+ mwexec_bg("/etc/rc.firmware pfSenseupgrade $path");
+ }
+ sleep(10);
+ while (is_subsystem_dirty('firmwarelock')) {
+ sleep(1);
+ echo ".";
+ }
+ sleep(10);
+ echo "Done. Rebooting...\n\n";
+ clear_subsystem_dirty('firmwarelock');
+}
+
+exec("rm -f /root/*.sha256");
+fclose($fp);
+
+?>
diff --git a/src/etc/rc.initial.halt b/src/etc/rc.initial.halt
new file mode 100755
index 0000000..9ff189b
--- /dev/null
+++ b/src/etc/rc.initial.halt
@@ -0,0 +1,61 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.halt
+ part of pfSense (www.pfSense.com)
+ Copyright (C)2004 Bachman Kharazmi
+
+ Originally part of m0n0wall as rc.initial.reboot (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ echo <<<EOD
+
+{$g['product_name']} will shutdown and halt system. This may take a few minutes, depending on your hardware.
+
+Do you want to proceed [y|n]?
+EOD;
+
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+
+ echo <<<EOD
+
+{$g['product_name']} will shutdown and halt system now.
+
+EOD;
+
+ system_halt();
+ }
+
+ fclose($fp);
+
+?>
diff --git a/src/etc/rc.initial.password b/src/etc/rc.initial.password
new file mode 100755
index 0000000..b5e01ed
--- /dev/null
+++ b/src/etc/rc.initial.password
@@ -0,0 +1,89 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.password
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+
+ require_once("config.inc");
+ require("auth.inc");
+ require_once("functions.inc");
+ require_once("shaper.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ echo "\n" . gettext('
+The webConfigurator admin password and privileges will be reset to the default (which is "' . strtolower($g['product_name']) . '").') . "\n" .
+ gettext('Do you want to proceed [y|n]?');
+
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+ if (isset($config['system']['webgui']['authmode']) &&
+ $config['system']['webgui']['authmode'] != "Local Database") {
+ echo "\n" . gettext('
+The User manager authentication server is set to "' . $config['system']['webgui']['authmode'] . '".') . "\n" .
+ gettext('Do you want to set it back to Local Database [y|n]?');
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+ $config['system']['webgui']['authmode'] = "Local Database";
+ }
+ }
+ $admin_user =& getUserEntryByUID(0);
+ if (!$admin_user) {
+ echo "Failed to locate the admin user account! Attempting to restore access.\n";
+ $admin_user = array();
+ $admin_user['uid'] = 0;
+ if (!is_array($config['system']['user'])) {
+ $config['system']['user'] = array();
+ }
+ $config['system']['user'][] = $admin_user;
+ }
+
+ $admin_user['name'] = "admin";
+ $admin_user['scope'] = "system";
+ $admin_user['priv'] = array("user-shell-access");
+
+ if (isset($admin_user['disabled'])) {
+ unset($admin_user['disabled']);
+ }
+
+ local_user_set_password($admin_user, strtolower($g['product_name']));
+ local_user_set($admin_user);
+ write_config(gettext("password changed from console menu"));
+
+ echo "\n" . gettext('
+The password for the webConfigurator has been reset and
+the default username has been set to "admin".') . "\n" .
+ gettext('
+Remember to set the password to something else than
+the default as soon as you have logged into the webConfigurator.') . "\n" .
+ gettext("Press ENTER to continue.");
+
+ fgets($fp);
+ }
+?>
diff --git a/src/etc/rc.initial.ping b/src/etc/rc.initial.ping
new file mode 100755
index 0000000..055d556
--- /dev/null
+++ b/src/etc/rc.initial.ping
@@ -0,0 +1,55 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.ping
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ echo "\nEnter a host name or IP address: ";
+
+ $pinghost = chop(fgets($fp));
+ if (is_ipaddrv4($pinghost) || is_hostname($pinghost)) {
+ $command = "ping";
+ } elseif (is_ipaddrv6($pinghost)) {
+ $command = "ping6";
+ }
+ if ($command) {
+ echo "\n";
+ passthru("/sbin/{$command} -c 3 -n " . escapeshellarg($pinghost));
+ echo "\nPress ENTER to continue.\n";
+ fgets($fp);
+ }
+
+ fclose($fp);
+?>
diff --git a/src/etc/rc.initial.reboot b/src/etc/rc.initial.reboot
new file mode 100755
index 0000000..38f9e3b
--- /dev/null
+++ b/src/etc/rc.initial.reboot
@@ -0,0 +1,61 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.reboot
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("filter.inc");
+ require_once("captiveportal.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ echo <<<EOD
+
+{$g['product_name']} will reboot. This may take a few minutes, depending on your hardware.
+
+Do you want to proceed [y|n]?
+EOD;
+
+ if (strcasecmp(chop(fgets($fp)), "y") == 0) {
+
+ echo <<<EOD
+
+{$g['product_name']} is rebooting now.
+
+EOD;
+
+ system_reboot_sync();
+ }
+
+ fclose($fp);
+
+?>
diff --git a/src/etc/rc.initial.setlanip b/src/etc/rc.initial.setlanip
new file mode 100755
index 0000000..e33a05a
--- /dev/null
+++ b/src/etc/rc.initial.setlanip
@@ -0,0 +1,556 @@
+#!/usr/local/bin/php-cgi -q
+<?php
+/* $Id$ */
+/*
+ rc.initial.setlanip
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$options = getopt("hn", array("dry-run", "help"));
+
+if (isset($options["h"]) || isset($options["help"])) {
+ echo "usage: /etc/rc.initial.setlanip [option ...]\n";
+ echo " -h, --help show this message\n";
+ echo " -n, --dry-run do not make any configuration changes\n";
+ return 0;
+}
+
+$dry_run = isset($options["n"]) || isset($options["dry-run"]);
+if ($dry_run) {
+ echo "DRY RUN MODE IS ON\n";
+}
+
+/* parse the configuration and include all functions used below */
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("rrd.inc");
+
+function console_prompt_for_yn ($prompt_text) {
+ global $fp;
+
+ $good_answer = false;
+
+ do {
+ echo "\n" . $prompt_text . " (y/n) ";
+ $yn = strtolower(chop(fgets($fp)));
+ if (($yn == "y") || ($yn == "yes")) {
+ $boolean_answer = true;
+ $good_answer = true;
+ }
+ if (($yn == "n") || ($yn == "no")) {
+ $boolean_answer = false;
+ $good_answer = true;
+ }
+ } while (!$good_answer);
+
+ return $boolean_answer;
+}
+
+function console_get_interface_from_ppp($realif) {
+ global $config;
+
+ if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
+ if ($realif == $ppp['if']) {
+ $ifaces = explode(",", $ppp['ports']);
+ return $ifaces[0];
+ }
+ }
+ }
+
+ return "";
+}
+
+function prompt_for_enable_dhcp_server($version = 4) {
+ global $config, $fp, $interface;
+ if ($interface == "wan") {
+ if ($config['interfaces']['lan']) {
+ return false;
+ }
+ }
+ /* only allow DHCP server to be enabled when static IP is
+ configured on this interface */
+ if ($version === 6) {
+ $is_ipaddr = is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6']);
+ } else {
+ $is_ipaddr = is_ipaddrv4($config['interfaces'][$interface]['ipaddr']);
+ }
+ if (!($is_ipaddr)) {
+ return false;
+ }
+
+ $label_DHCP = ($version === 6) ? "DHCP6" : "DHCP";
+ $upperifname = strtoupper($interface);
+ return console_prompt_for_yn (sprintf(gettext("Do you want to enable the %s server on %s?"), $label_DHCP, $upperifname));
+}
+
+function get_interface_config_description($iface) {
+ global $config;
+ $c = $config['interfaces'][$iface];
+ if (!$c) {
+ return null;
+ }
+ $if = $c['if'];
+ $result = $if;
+ $result2 = array();
+ $ipaddr = $c['ipaddr'];
+ $ipaddrv6 = $c['ipaddrv6'];
+ if (is_ipaddr($ipaddr)) {
+ $result2[] = "static";
+ } else if ($ipaddr == "dhcp") {
+ $result2[] = "dhcp";
+ }
+ if (is_ipaddr($ipaddrv6)) {
+ $result2[] = "staticv6";
+ } else if ($ipaddrv6 == "dhcp6") {
+ $result2[] = "dhcp6";
+ }
+ if (count($result2)) {
+ $result .= " - " . implode(", ", $result2);
+ }
+ return $result;
+}
+
+$fp = fopen('php://stdin', 'r');
+
+/* build an interface collection */
+$ifdescrs = get_configured_interface_with_descr(false, true);
+$count = count($ifdescrs);
+
+/* grab interface that we will operate on, unless there is only one interface */
+if ($count > 1) {
+ echo "Available interfaces:\n\n";
+ $x=1;
+ foreach ($ifdescrs as $iface => $ifdescr) {
+ $config_descr = get_interface_config_description($iface);
+ echo "{$x} - {$ifdescr} ({$config_descr})\n";
+ $x++;
+ }
+ echo "\nEnter the number of the interface you wish to configure: ";
+ $intnum = chop(fgets($fp));
+} else {
+ $intnum = $count;
+}
+
+if ($intnum < 1) {
+ return;
+}
+if ($intnum > $count) {
+ return;
+}
+
+$index = 1;
+foreach ($ifdescrs as $ifname => $ifdesc) {
+ if ($intnum == $index) {
+ $interface = $ifname;
+ break;
+ } else {
+ $index++;
+ }
+}
+if (!$interface) {
+ echo "Invalid interface!\n";
+ return;
+}
+
+$ifaceassigned = "";
+
+function next_unused_gateway_name($interface) {
+ global $g, $config;
+ $new_name = "GW_" . strtoupper($interface);
+
+ if (!is_array($config['gateways']['gateway_item'])) {
+ return $new_name;
+ }
+ $count = 1;
+ do {
+ $existing = false;
+ foreach ($config['gateways']['gateway_item'] as $item) {
+ if ($item['name'] === $new_name) {
+ $existing = true;
+ break;
+ }
+ }
+ if ($existing) {
+ $count += 1;
+ $new_name = "GW_" . strtoupper($interface) . "_" . $count;
+ }
+ } while ($existing);
+ return $new_name;
+}
+
+function add_gateway_to_config($interface, $gatewayip, $inet_type) {
+ global $g, $config, $dry_run;
+ if (!is_array($config['gateways']['gateway_item'])) {
+ $config['gateways']['gateway_item'] = array();
+ }
+ $a_gateways = &$config['gateways']['gateway_item'];
+ if ($dry_run) {
+ print_r($a_gateways);
+ }
+ $new_name = '';
+ $is_default = true;
+ foreach ($a_gateways as $item) {
+ if ($item['ipprotocol'] === $inet_type) {
+ if (isset($item['defaultgw'])) {
+ $is_default = false;
+ }
+ if (($item['interface'] === $interface) && ($item['gateway'] === $gatewayip)) {
+ $new_name = $item['name'];
+ }
+ }
+ }
+ if ($new_name == '') {
+ $new_name = next_unused_gateway_name($interface);
+ $item = array(
+ "interface" => $interface,
+ "gateway" => $gatewayip,
+ "name" => $new_name,
+ "weight" => 1,
+ "ipprotocol" => $inet_type,
+ "interval" => true,
+ "descr" => "Interface $interface Gateway",
+ "defaultgw" => $is_default
+ );
+ if ($dry_run) {
+ print_r($item);
+ }
+ $a_gateways[] = $item;
+ }
+
+ return $new_name;
+}
+
+function console_configure_ip_address($version) {
+ global $g, $config, $interface, $restart_dhcpd, $ifaceassigned, $fp;
+
+ $label_IPvX = ($version === 6) ? "IPv6" : "IPv4";
+ $maxbits = ($version === 6) ? 127 : 31;
+ $label_DHCP = ($version === 6) ? "DHCP6" : "DHCP";
+
+ $upperifname = strtoupper($interface);
+
+ if ($interface == "wan") {
+ if (console_prompt_for_yn (sprintf(gettext("Configure %s address %s interface via %s?"), $label_IPvX, $upperifname, $label_DHCP))) {
+ $ifppp = console_get_interface_from_ppp(get_real_interface("wan"));
+ if (!empty($ifppp)) {
+ $ifaceassigned = $ifppp;
+ }
+ $intip = ($version === 6) ? "dhcp6" : "dhcp";
+ $intbits = "";
+ $isintdhcp = true;
+ $restart_dhcpd = true;
+ }
+ }
+
+ if ($isintdhcp == false or $interface <> "wan") {
+ while (true) {
+ do {
+ echo "\n" . sprintf(gettext("Enter the new %s %s address. Press <ENTER> for none:"),
+ $upperifname, $label_IPvX) . "\n> ";
+ $intip = chop(fgets($fp));
+ $is_ipaddr = ($version === 6) ? is_ipaddrv6($intip) : is_ipaddrv4($intip);
+ if ($is_ipaddr && is_ipaddr_configured($intip, $interface, true)) {
+ $ip_conflict = true;
+ echo gettext("This IP address conflicts with another interface or a VIP") . "\n";
+ } else {
+ $ip_conflict = false;
+ }
+ } while (($ip_conflict === true) || !($is_ipaddr || $intip == ''));
+ if ($intip != '') {
+ echo "\n" . sprintf(gettext("Subnet masks are entered as bit counts (as in CIDR notation) in %s."),
+ $g['product_name']) . "\n";
+ if ($version === 6) {
+ echo "e.g. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00 = 120\n";
+ echo " ffff:ffff:ffff:ffff:ffff:ffff:ffff:0 = 112\n";
+ echo " ffff:ffff:ffff:ffff:ffff:ffff:0:0 = 96\n";
+ echo " ffff:ffff:ffff:ffff:ffff:0:0:0 = 80\n";
+ echo " ffff:ffff:ffff:ffff:0:0:0:0 = 64\n";
+ } else {
+ echo "e.g. 255.255.255.0 = 24\n";
+ echo " 255.255.0.0 = 16\n";
+ echo " 255.0.0.0 = 8\n";
+ }
+ do {
+ $upperifname = strtoupper($interface);
+ echo "\n" . sprintf(gettext("Enter the new %s %s subnet bit count (1 to %s):"),
+ $upperifname, $label_IPvX, $maxbits) . "\n> ";
+ $intbits = chop(fgets($fp));
+ $intbits_ok = is_numeric($intbits) && (($intbits >= 1) && ($intbits <= $maxbits));
+ $restart_dhcpd = true;
+
+ if ($version === 4 && $intbits < $maxbits) {
+ if ($intip == gen_subnet($intip, $intbits)) {
+ echo gettext("You cannot set network address to an interface");
+ continue 2;
+ $intbits_ok = false;
+ } else if ($intip == gen_subnet_max($intip, $intbits)) {
+ echo gettext("You cannot set broadcast address to an interface");
+ continue 2;
+ $intbits_ok = false;
+ }
+ }
+ } while (!$intbits_ok);
+
+ if ($version === 6) {
+ $subnet = gen_subnetv6($intip, $intbits);
+ } else {
+ $subnet = gen_subnet($intip, $intbits);
+ }
+ do {
+ echo "\n" . sprintf(gettext("For a WAN, enter the new %s %s upstream gateway address."), $upperifname, $label_IPvX) . "\n" .
+ gettext("For a LAN, press <ENTER> for none:") . "\n> ";
+ $gwip = chop(fgets($fp));
+ $is_ipaddr = ($version === 6) ? is_ipaddrv6($gwip) : is_ipaddrv4($gwip);
+ $is_in_subnet = $is_ipaddr && ip_in_subnet($gwip, $subnet . "/" . $intbits);
+ if ($gwip != '') {
+ if (!$is_ipaddr) {
+ echo sprintf(gettext("not an %s IP address!"), $label_IPvX) . "\n";
+ } else if (!$is_in_subnet) {
+ echo gettext("not in subnet!") . "\n";
+ }
+ }
+ } while (!($gwip == '' || ($is_ipaddr && $is_in_subnet)));
+
+ if ($gwip != '') {
+ $inet_type = ($version === 6) ? "inet6" : "inet";
+ $gwname = add_gateway_to_config($interface, $gwip, $inet_type);
+ }
+ }
+ $ifppp = console_get_interface_from_ppp(get_real_interface($interface));
+ if (!empty($ifppp)) {
+ $ifaceassigned = $ifppp;
+ }
+ break;
+ }
+ }
+
+ return array($intip, $intbits, $gwname);
+}
+
+list($intip, $intbits, $gwname) = console_configure_ip_address(4);
+list($intip6, $intbits6, $gwname6) = console_configure_ip_address(6);
+
+if (!empty($ifaceassigned)) {
+ $config['interfaces'][$interface]['if'] = $ifaceassigned;
+}
+$config['interfaces'][$interface]['ipaddr'] = $intip;
+$config['interfaces'][$interface]['subnet'] = $intbits;
+$config['interfaces'][$interface]['gateway'] = $gwname;
+$config['interfaces'][$interface]['ipaddrv6'] = $intip6;
+$config['interfaces'][$interface]['subnetv6'] = $intbits6;
+$config['interfaces'][$interface]['gatewayv6'] = $gwname6;
+$config['interfaces'][$interface]['enable'] = true;
+
+function console_configure_dhcpd($version = 4) {
+ global $g, $config, $restart_dhcpd, $fp, $interface, $dry_run, $intip, $intbits, $intip6, $intbits6;
+
+ $label_IPvX = ($version === 6) ? "IPv6" : "IPv4";
+ $dhcpd = ($version === 6) ? "dhcpdv6" : "dhcpd";
+
+ if ($g['services_dhcp_server_enable'] && prompt_for_enable_dhcp_server($version)) {
+ $subnet_start = ($version === 6) ? gen_subnetv6($intip6, $intbits6) : gen_subnet($intip, $intbits);
+ $subnet_end = ($version === 6) ? gen_subnetv6_max($intip6, $intbits6) : gen_subnet_max($intip, $intbits);
+ do {
+ do {
+ echo sprintf(gettext("Enter the start address of the %s client address range:"), $label_IPvX) . " ";
+ $dhcpstartip = chop(fgets($fp));
+ if ($dhcpstartip === "") {
+ fclose($fp);
+ return 0;
+ }
+ $is_ipaddr = ($version === 6) ? is_ipaddrv6($dhcpstartip) : is_ipaddrv4($dhcpstartip);
+ $is_inrange = is_inrange($dhcpstartip, $subnet_start, $subnet_end);
+ if (!$is_inrange) {
+ echo gettext("This IP address must be in the interface's subnet") . "\n";
+ }
+ } while (!$is_ipaddr || !$is_inrange);
+
+ do {
+ echo sprintf(gettext("Enter the end address of the %s client address range:"), $label_IPvX) . " ";
+ $dhcpendip = chop(fgets($fp));
+ if ($dhcpendip === "") {
+ fclose($fp);
+ return 0;
+ }
+ $is_ipaddr = ($version === 6) ? is_ipaddrv6($dhcpendip) : is_ipaddrv4($dhcpendip);
+ $is_inrange = is_inrange($dhcpendip, $subnet_start, $subnet_end);
+ if (!$is_inrange) {
+ echo gettext("This IP address must be in the interface's subnet") . "\n";
+ }
+ $not_inorder = ($version === 6) ? (inet_pton($dhcpendip) < inet_pton($dhcpstartip)) : ip_less_than($dhcpendip, $dhcpstartip);
+ if ($not_inorder) {
+ echo gettext("The end address of the DHCP range must be >= the start address") . "\n";
+ }
+ } while (!$is_ipaddr || !$is_inrange);
+ } while ($not_inorder);
+ $restart_dhcpd = true;
+ $config[$dhcpd][$interface]['enable'] = true;
+ $config[$dhcpd][$interface]['range']['from'] = $dhcpstartip;
+ $config[$dhcpd][$interface]['range']['to'] = $dhcpendip;
+ } else {
+ if (isset($config[$dhcpd][$interface]['enable'])) {
+ unset($config[$dhcpd][$interface]['enable']);
+ printf(gettext("Disabling %s DHCPD..."), $label_IPvX);
+ $restart_dhcpd = true;
+ }
+ }
+ return 1;
+}
+
+if (console_configure_dhcpd(4) == 0) {
+ return 0;
+}
+if (console_configure_dhcpd(6) == 0) {
+ return 0;
+}
+
+//*****************************************************************************
+
+if ($config['system']['webgui']['protocol'] == "https") {
+
+ if (console_prompt_for_yn (gettext("Do you want to revert to HTTP as the webConfigurator protocol?"))) {
+ $config['system']['webgui']['protocol'] = "http";
+ $restart_webgui = true;
+ }
+}
+
+if (isset($config['system']['webgui']['noantilockout'])) {
+ echo "\n" . sprintf(gettext("Note: the anti-lockout rule on %s has been re-enabled."), $interface) . "\n";
+ unset($config['system']['webgui']['noantilockout']);
+}
+
+if ($config['interfaces']['lan']) {
+ if ($config['dhcpd']) {
+ if ($config['dhcpd']['wan']) {
+ unset($config['dhcpd']['wan']);
+ }
+ }
+ if ($config['dhcpdv6']) {
+ if ($config['dhcpdv6']['wan']) {
+ unset($config['dhcpdv6']['wan']);
+ }
+ }
+}
+
+if (!$config['interfaces']['lan']) {
+ unset($config['interfaces']['lan']);
+ if ($config['dhcpd']['lan']) {
+ unset($config['dhcpd']['lan']);
+ }
+ if ($config['dhcpdv6']['lan']) {
+ unset($config['dhcpdv6']['lan']);
+ }
+ unset($config['shaper']);
+ unset($config['ezshaper']);
+ unset($config['nat']);
+ if (!$dry_run) {
+ system("rm /var/dhcpd/var/db/* >/dev/null 2>/dev/null");
+ $restart_dhcpd = true;
+ }
+}
+
+$upperifname = strtoupper($interface);
+if (!$dry_run) {
+ echo "\nPlease wait while the changes are saved to {$upperifname}...";
+ write_config(sprintf(gettext("%s IP configuration from console menu"), $interface));
+ interface_reconfigure(strtolower($upperifname));
+ echo "\n Reloading filter...";
+ filter_configure_sync();
+ echo "\n Reloading routing configuration...";
+ system_routing_configure();
+ if ($restart_dhcpd) {
+ echo "\n DHCPD...";
+ services_dhcpd_configure();
+ }
+ if ($restart_webgui) {
+ echo "\n Restarting webConfigurator... ";
+ mwexec("/etc/rc.restart_webgui");
+ }
+}
+
+if ($intip != '') {
+ if (is_ipaddr($intip)) {
+ echo "\n\n" . sprintf(gettext("The IPv4 %s address has been set to %s"),
+ $upperifname, "{$intip}/{$intbits}") . "\n";
+ } else {
+ echo "\n\n" . sprintf(gettext("The IPv4 %s address has been set to %s"),
+ $upperifname, $intip) . "\n";
+ }
+}
+if ($intip6 != '') {
+ if (is_ipaddr($intip6)) {
+ echo "\n\n" . sprintf(gettext("The IPv6 %s address has been set to %s"),
+ $upperifname, "${intip6}/${intbits6}") . "\n";
+ } else {
+ echo "\n\n" . sprintf(gettext("The IPv6 %s address has been set to %s"),
+ $upperifname, $intip6) . "\n";
+ }
+}
+
+if ($intip != '' || $intip6 != '') {
+ if (count($ifdescrs) == "1" or $interface == "lan") {
+ if ($debug) {
+ echo "ifdescrs count is " . count($ifdescrs) . "\n";
+ echo "interface is {$interface} \n";
+ }
+ echo gettext('You can now access the webConfigurator by opening the following URL in your web browser:') . "\n";
+ if (!empty($config['system']['webgui']['port'])) {
+ $webuiport = $config['system']['webgui']['port'];
+ if ($intip != '') {
+ echo " {$config['system']['webgui']['protocol']}://{$intip}:{$webuiport}/\n";
+ }
+ if ($intip6 != '') {
+ if (is_ipaddr($intip6)) {
+ echo " {$config['system']['webgui']['protocol']}://[{$intip6}]:{$webuiport}/\n";
+ } else {
+ echo " {$config['system']['webgui']['protocol']}://{$intip6}:{$webuiport}/\n";
+ }
+ }
+ } else {
+ if ($intip != '') {
+ echo " {$config['system']['webgui']['protocol']}://{$intip}/\n";
+ }
+ if ($intip6 != '') {
+ if (is_ipaddr($intip6)) {
+ echo " {$config['system']['webgui']['protocol']}://[{$intip6}]/\n";
+ } else {
+ echo " {$config['system']['webgui']['protocol']}://{$intip6}/\n";
+ }
+ }
+ }
+ }
+}
+
+echo "\n" . gettext('Press <ENTER> to continue.');
+
+fgets($fp);
+fclose($fp);
+
+?>
diff --git a/src/etc/rc.initial.setports b/src/etc/rc.initial.setports
new file mode 100755
index 0000000..147912f
--- /dev/null
+++ b/src/etc/rc.initial.setports
@@ -0,0 +1,51 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.setports
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("config.console.inc");
+ require_once("functions.inc");
+ require_once("filter.inc");
+ require_once("shaper.inc");
+ require_once("ipsec.inc");
+ require_once("vpn.inc");
+ require_once("captiveportal.inc");
+ require_once("rrd.inc");
+
+ set_networking_interfaces_ports();
+
+ reload_interfaces_sync();
+
+ /* reload graphing functions */
+ enable_rrd_graphing();
+
+?>
diff --git a/src/etc/rc.initial.store_config_to_removable_device b/src/etc/rc.initial.store_config_to_removable_device
new file mode 100755
index 0000000..a40df6f
--- /dev/null
+++ b/src/etc/rc.initial.store_config_to_removable_device
@@ -0,0 +1,93 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.initial.store_config_to_removable_device
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("util.inc");
+
+ $fp = fopen('php://stdin', 'r');
+
+ do {
+ $dirs = array();
+ $dirs = return_dir_as_array("/var/db/pfi/");
+ if (!is_array($dirs)) {
+ echo "\nNo capable storage devices detected.\n";
+ fclose($fp);
+ return;
+ }
+ echo "\nDevices capable of config.xml storage:\n";
+ foreach ($dirs as $dir) {
+ preg_match_all("/capable\_(.*)/", $dir, $match_array);
+ echo $match_array[1][0] . " ";
+ }
+ echo "\n\n";
+ echo "Enter the device that you wish the";
+ echo "\n";
+ echo "{$g['product_name']} configuration file to reside on: ";
+ $move_config_to_device = chop(fgets($fp));
+ if ($move_config_to_device == "") {
+ fclose($fp);
+ return 0;
+ }
+ } while (!$move_config_to_device);
+
+ mwexec("/bin/mkdir -p /tmp/mnt/cf");
+
+ $status = mwexec("/sbin/mount -w -t msdosfs /dev/{$move_config_to_device} /tmp/mnt/cf");
+ if (!$status) {
+ echo "Error while mounting {$move_config_to_device}.\n";
+ fclose($fp);
+ return;
+ }
+
+ echo "\n\nProcessing: ";
+ $lockkey = lock('config');
+ echo "moving...";
+ mwexec("mkdir -p /tmp/mnt/cf/conf/");
+ mwexec("/bin/mv /cf/conf/config.xml /tmp/mnt/cf/conf/");
+ echo "removing old...";
+ echo " nullfs... ";
+ system("/sbin/umount /cf/conf");
+ system("/sbin/umount /conf");
+ mwexec("/bin/rm -rf /conf/*.*");
+ /* use nullfs to mount */
+ system("/sbin/mount_nullfs /tmp/mnt/cf/conf /conf");
+ system("/sbin/mount_nullfs /tmp/mnt/cf /cf");
+ echo "linking...";
+ mwexec("/bin/rm -rf /var/db/pfi");
+ unlock($lockkey);
+ echo "done.\n";
+ echo "\nYour configuration has been moved to {$move_config_to_device}\n";
+ touch("/tmp/config_moved");
+ fclose($fp);
+?>
diff --git a/src/etc/rc.initial.toggle_sshd b/src/etc/rc.initial.toggle_sshd
new file mode 100755
index 0000000..695a6c1
--- /dev/null
+++ b/src/etc/rc.initial.toggle_sshd
@@ -0,0 +1,75 @@
+#! /usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.initial.toggle_sshd
+ sshd - Modified to work on disk based system
+ Copyright 2004 Scott K Ullrich
+
+ Original Copyright (C) 2004 Fred Mol <fredmol@xs4all.nl>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+
+conf_mount_rw();
+
+$fp = fopen('php://stdin', 'r');
+
+if (isset($config['system']['enablesshd'])) {
+ echo "SSHD is currently enabled. Would you like to disable? [y/n]? ";
+ $yn = chop(fgets($fp));
+ if ($yn[0] == "y") {
+ unset($config['system']['enablesshd']);
+ echo "\nWriting configuration...";
+ write_config();
+ echo " done.\n";
+ echo "\nDisabling SSHD...";
+ send_event("service reload sshd");
+ echo "\nReloading firewall rules.";
+ filter_configure();
+ echo " done.\n";
+ exec("ps awux | grep '/usr/sbin/sshd' | grep -v grep | awk '{print $2}' | xargs kill");
+ }
+
+} else {
+ echo "SSHD is currently disabled. Would you like to enable? [y/n]? ";
+ $yn = chop(fgets($fp));
+ if ($yn[0] == "y") {
+ $config['system']['enablesshd'] = true;
+ echo "\nWriting configuration...";
+ write_config();
+ echo " done.\n";
+ echo "\nEnabling SSHD...";
+ send_event("service reload sshd");
+ echo "\nReloading firewall rules.";
+ filter_configure();
+ echo " done.\n\n";
+ }
+}
+
+fclose($fp);
+
+conf_mount_ro();
diff --git a/src/etc/rc.interfaces_carp_configure b/src/etc/rc.interfaces_carp_configure
new file mode 100755
index 0000000..33a0b38
--- /dev/null
+++ b/src/etc/rc.interfaces_carp_configure
@@ -0,0 +1,39 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.interfaces_carp_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+interfaces_carp_configure();
+
+?>
diff --git a/src/etc/rc.interfaces_lan_configure b/src/etc/rc.interfaces_lan_configure
new file mode 100755
index 0000000..2924cf9
--- /dev/null
+++ b/src/etc/rc.interfaces_lan_configure
@@ -0,0 +1,39 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.interfaces_lan_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+interface_configure("lan");
+
+?>
diff --git a/src/etc/rc.interfaces_opt_configure b/src/etc/rc.interfaces_opt_configure
new file mode 100755
index 0000000..c00877a
--- /dev/null
+++ b/src/etc/rc.interfaces_opt_configure
@@ -0,0 +1,41 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.interfaces_opt_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("vpn.inc");
+require_once("captiveportal.inc");
+
+interfaces_configure();
+
+?>
diff --git a/src/etc/rc.interfaces_wan_configure b/src/etc/rc.interfaces_wan_configure
new file mode 100755
index 0000000..9b064d0
--- /dev/null
+++ b/src/etc/rc.interfaces_wan_configure
@@ -0,0 +1,50 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.interfaces_wan_configure
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+
+if (isset($_GET['interface'])) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = str_replace("\n", "", $argv[1]);
+}
+if (empty($argument)) {
+ interface_configure("wan");
+} else {
+ if (!empty($config['interfaces'][$argument])) {
+ interface_configure($argument);
+ }
+}
+
+?>
diff --git a/src/etc/rc.kill_states b/src/etc/rc.kill_states
new file mode 100755
index 0000000..715c860
--- /dev/null
+++ b/src/etc/rc.kill_states
@@ -0,0 +1,94 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.kill_states
+ Copyright (C) 2013 Renato Botelho (garga@pfsense.org)
+ part of pfSense (https://www.pfsense.org)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("globals.inc");
+require_once("config.inc");
+require_once("interfaces.inc");
+require_once("util.inc");
+
+// Do not process while booting
+if (platform_booting()) {
+ return;
+}
+
+/* Interface address to cleanup states */
+$interface = str_replace("\n", "", $argv[1]);
+
+/* IP address to cleanup states */
+$local_ip = str_replace("\n", "", $argv[2]);
+
+if (empty($interface) || !does_interface_exist($interface)) {
+ log_error("rc.kill_states: Invalid interface '{$interface}'");
+ return;
+}
+
+if (!empty($local_ip)) {
+ list($local_ip, $subnet_bits) = explode("/", $local_ip);
+
+ if (empty($subnet_bits)) {
+ $subnet_bits = "32";
+ }
+
+ if (!is_ipaddr($local_ip)) {
+ log_error("rc.kill_states: Invalid IP address '{$local_ip}'");
+ return;
+ }
+}
+
+if (!isset($config['system']['kill_states'])) {
+ if (!empty($local_ip)) {
+ log_error("rc.kill_states: Removing states for IP {$local_ip}/{$subnet_bits}");
+ $nat_states = exec_command("/sbin/pfctl -i {$interface} -ss | " .
+ "/usr/bin/egrep '\-> +{$local_ip}:[0-9]+ +\->'");
+
+ $cleared_states = array();
+ foreach (explode("\n", $nat_states) as $nat_state) {
+ if (preg_match_all('/([\d\.]+):[\d]+[\s->]+/i', $nat_state, $matches, PREG_SET_ORDER) != 3) {
+ continue;
+ }
+
+ $src = $matches[0][1];
+ $dst = $matches[2][1];
+
+ if (empty($src) || empty($dst) || in_array("{$src},{$dst}", $cleared_states)) {
+ continue;
+ }
+
+ $cleared_states[] = "{$src},{$dst}";
+ pfSense_kill_states($src, $dst);
+ }
+
+ pfSense_kill_states("0.0.0.0/0", "{$local_ip}/{$subnet_bits}");
+ pfSense_kill_states("{$local_ip}/{$subnet_bits}");
+ pfSense_kill_srcstates("{$local_ip}/{$subnet_bits}");
+ }
+ log_error("rc.kill_states: Removing states for interface {$interface}");
+ mwexec("/sbin/pfctl -i {$interface} -Fs", true);
+}
diff --git a/src/etc/rc.linkup b/src/etc/rc.linkup
new file mode 100755
index 0000000..153cd49
--- /dev/null
+++ b/src/etc/rc.linkup
@@ -0,0 +1,165 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.linkup - devd hotplug actions
+ part of pfSense
+
+ Copyright (C) 2003-2005 Scott Ullrich <sullrich@gmail.com>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("globals.inc");
+require_once("config.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("interfaces.inc");
+
+if (platform_booting()) {
+ return;
+}
+
+function handle_argument_group($iface, $argument2) {
+ global $config;
+
+ if (!is_array($config['interfaces'][$iface])) {
+ log_error("Cannot find interface configuration for {$iface}");
+ return;
+ }
+
+ if (!isset($config['interfaces'][$iface]['enable'])) {
+ if (!platform_booting()) {
+ log_error("Linkup detected on disabled interface...Ignoring");
+ }
+ return;
+ }
+
+ $ipaddr = $config['interfaces'][$iface]['ipaddr'];
+ $ip6addr = $config['interfaces'][$iface]['ipaddrv6'];
+ $staticv4 = false;
+ if (empty($ipaddr)) {
+ $staticv4 = true;
+ } else {
+ $staticv4 = is_ipaddrv4($ipaddr);
+ }
+ $staticv6 = false;
+ if (empty($ip6addr)) {
+ $staticv6 = true;
+ } else {
+ $staticv6 = is_ipaddrv6($ip6addr);
+ }
+ if ($staticv4 === true && $staticv6 === true) {
+ $friendly = convert_friendly_interface_to_friendly_descr($iface);
+ log_error("Hotplug event detected for {$friendly}({$iface}) but ignoring since interface is configured with static IP ({$ipaddr} {$ip6addr})");
+ interfaces_staticarp_configure($iface);
+ switch ($argument2) {
+ case 'start':
+ case 'up':
+ $iface = get_real_interface($iface);
+ /* NOTE: Do not generate event for OpenVPN since the daemon does that for us. */
+ if (substr($iface, 0, 4) != "ovpn") {
+ send_event("interface newip {$iface}");
+ }
+ break;
+ }
+ } else {
+ switch ($argument2) {
+ case "stop":
+ case "down":
+ log_error("DEVD Ethernet detached event for {$iface}");
+ interface_bring_down($iface);
+ break;
+ case "start":
+ case "up":
+ log_error("DEVD Ethernet attached event for {$iface}");
+ log_error("HOTPLUG: Configuring interface {$iface}");
+ require_once("vpn.inc");
+ require_once("captiveportal.inc");
+ // Do not try to readd to bridge otherwise em(4) has problems
+ interface_configure($iface, true, true);
+ break;
+ }
+ }
+}
+
+if (isset($_GET['interface'])) {
+ if (!empty($_GET['interface'])) {
+ $realiface = $_GET['interface'];
+ }
+ $action = $_GET['action'];
+} else {
+ if ($argc < 3) {
+ log_error("HOTPLUG event: The required number of parameters not passed!");
+ return;
+ }
+ $action = $argv[1];
+ $realiface = $argv[2];
+}
+
+switch ($action) {
+ case "start":
+ case "stop":
+ break;
+ default:
+ log_error("HOTPLUG event: Action parameter ($action) passed is wrong - only start/stop/up/down are allowed!");
+ return;
+ /* NOTREACHED */
+ break;
+}
+
+if (!empty($realiface)) {
+ if (substr($realiface, 0, 4) == 'ovpn') {
+ log_error("Ignoring link event for ovpn interface");
+ return;
+ }
+ $rclinkuplock = lock("rclinkup{$realiface}", LOCK_EX);
+ $interface = convert_real_interface_to_friendly_interface_name($realiface);
+ if (!empty($interface)) {
+ handle_argument_group($interface, $action);
+ }
+ if ($action == 'start') {
+ /* Check if there is any child on this one as ppp types and trigger them */
+ if (is_array($config['ppps']['ppp'])) {
+ foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
+ if ($ppp['type'] == 'ppp') {
+ continue;
+ }
+ $ports = explode(',', $ppp['ports']);
+ foreach ($ports as $pid => $parent_if) {
+ /* The loop here is because ppp types can have real and assigned interfaces as members */
+ $tmpiface = get_real_interface($parent_if);
+ if ($tmpiface != $realiface) {
+ continue;
+ }
+ $tmpiface = convert_real_interface_to_friendly_interface_name($ppp['if']);
+ if (!empty($tmpiface)) {
+ interface_configure($tmpiface, true, true);
+ }
+ }
+ }
+ }
+ }
+ unlock($rclinkuplock);
+}
+?>
diff --git a/src/etc/rc.nanobsd_switch_boot_slice b/src/etc/rc.nanobsd_switch_boot_slice
new file mode 100755
index 0000000..58dbcc6
--- /dev/null
+++ b/src/etc/rc.nanobsd_switch_boot_slice
@@ -0,0 +1,27 @@
+#!/usr/local/bin/php-cgi -q
+<?php
+require_once("globals.inc");
+require_once("config.inc");
+require_once("pfsense-utils.inc");
+
+global $g;
+global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
+global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
+global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
+nanobsd_detect_slice_info();
+
+if ($g['platform'] != "nanobsd") {
+ echo "This script can only be used on NanoBSD (embedded) images.\n";
+ return 1;
+}
+
+echo "Boot slice : {$BOOTFLASH} ({$BOOT_DEVICE})\n";
+echo "Active slice: {$ACTIVE_SLICE}\n\n";
+
+echo "Switching active slice...";
+nanobsd_switch_boot_slice();
+echo "Done.\n\n";
+nanobsd_detect_slice_info();
+echo "Boot slice : {$BOOTFLASH} ({$BOOT_DEVICE})\n";
+echo "Active slice: {$ACTIVE_SLICE}\n\n";
+?>
diff --git a/src/etc/rc.newipsecdns b/src/etc/rc.newipsecdns
new file mode 100755
index 0000000..7c5428a
--- /dev/null
+++ b/src/etc/rc.newipsecdns
@@ -0,0 +1,61 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.newipsecdns
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2007 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2009 Seth Mos <seth.mos@dds.nl>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("util.inc");
+require_once("config.inc");
+require_once("gwlb.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("auth.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+
+/* make sure to wait until the boot scripts have finished */
+if (file_exists("{$g['varrun_path']}/booting")) {
+ return;
+}
+
+if (isset($config['ipsec']['enable'])) {
+ sleep(15);
+ log_error("IPSEC: One or more IPsec tunnel endpoints has changed its IP. Refreshing.");
+} else {
+ return;
+}
+
+$ipseclck = lock('ipsecdns', LOCK_EX);
+
+vpn_ipsec_configure();
+
+unlock($ipseclck);
+?>
diff --git a/src/etc/rc.newroutedns b/src/etc/rc.newroutedns
new file mode 100755
index 0000000..de3a081
--- /dev/null
+++ b/src/etc/rc.newroutedns
@@ -0,0 +1,59 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.newroutedns
+ Copyright (C) 2013 Renato Botelho <garga@pfsense.org>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("util.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("system.inc");
+
+/* make sure to wait until the boot scripts have finished */
+if (file_exists("{$g['varrun_path']}/booting")) {
+ return;
+}
+
+$staticroutes = get_staticroutes();
+
+if (count($staticroutes)) {
+ log_error("Static Routes: One or more aliases used for routing has changed its IP. Refreshing.");
+} else {
+ return;
+}
+
+$routelck = lock('routedns', LOCK_EX);
+
+/* We will walk the list of hostnames found in static routes
+ * configuration. Since we are already triggered by filterdns
+ * that a hostname has changed we can proceed to compare the
+ * new IP address with the old address from the DNS cache.
+ */
+system_staticroutes_configure();
+
+unlock($routelck);
+?>
diff --git a/src/etc/rc.newwanip b/src/etc/rc.newwanip
new file mode 100755
index 0000000..01d211c
--- /dev/null
+++ b/src/etc/rc.newwanip
@@ -0,0 +1,268 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.newwanip
+ Copyright (C) 2006 Scott Ullrich (sullrich@gmail.com)
+ part of pfSense (https://www.pfsense.org)
+
+ Originally part of m0n0wall (http://m0n0.ch)
+ Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+require_once("openvpn.inc");
+require_once("IPv6.inc");
+require_once("rrd.inc");
+
+function restart_packages() {
+ global $oldip, $curwanip, $g;
+
+ /* restart packages */
+ system_ntp_configure(false);
+ mwexec_bg("/usr/local/sbin/ntpdate_sync_once.sh", true);
+ log_error("{$g['product_name']} package system has detected an IP change or dynamic WAN reconnection - $oldip -> $curwanip - Restarting packages.");
+ send_event("service reload packages");
+}
+
+/* Interface IP address has changed */
+if (isset($_GET['interface'])) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = str_replace("\n", "", $argv[1]);
+}
+
+log_error("rc.newwanip: Info: starting on {$argument}.");
+
+if (empty($argument)) {
+ $interface = "wan";
+ $interface_real = get_real_interface();
+} else {
+ $interface = convert_real_interface_to_friendly_interface_name($argument);
+ $interface_real = $argument;
+}
+
+$interface_descr = convert_friendly_interface_to_friendly_descr($interface);
+
+/* If the interface is configured and not enabled, bail. We do not need to change settings for disabled interfaces. #3313 */
+if (is_array($config['interfaces'][$interface]) && !isset($config['interfaces'][$interface]['enable'])) {
+ log_error("Interface is disabled, nothing to do.");
+ return;
+}
+
+if (empty($argument)) {
+ $curwanip = get_interface_ip();
+} else {
+ $curwanip = find_interface_ip($interface_real, true);
+ if ($curwanip == "") {
+ $curwanip = get_interface_ip($interface);
+ }
+}
+
+if (!platform_booting()) {
+ log_error("rc.newwanip: on (IP address: {$curwanip}) (interface: {$interface_descr}[{$interface}]) (real interface: {$interface_real}).");
+}
+
+/*
+ * NOTE: Take care of openvpn, no-ip or similar interfaces if you generate the event to reconfigure an interface.
+ * i.e. OpenVPN might be in tap mode and not have an ip.
+ */
+if ($curwanip == "0.0.0.0" || !is_ipaddr($curwanip)) {
+ if (substr($interface_real, 0, 4) != "ovpn") {
+ if (!empty($config['interfaces'][$interface]['ipaddr'])) {
+ log_error("rc.newwanip: Failed to update {$interface} IP, restarting...");
+ send_event("interface reconfigure {$interface}");
+ return;
+ }
+ }
+}
+
+/* XXX: This really possible? */
+if (empty($interface)) {
+ if (platform_booting()) {
+ return;
+ }
+ filter_configure();
+ restart_packages();
+ return;
+}
+
+$oldip = "0.0.0.0";
+if (file_exists("{$g['vardb_path']}/{$interface}_cacheip")) {
+ $oldip = file_get_contents("{$g['vardb_path']}/{$interface}_cacheip");
+}
+
+/* regenerate resolv.conf if DNS overrides are allowed */
+if (!platform_booting()) {
+ system_resolvconf_generate(true);
+}
+
+/* write the current interface IP to file */
+if (is_ipaddr($curwanip)) {
+ @file_put_contents("{$g['vardb_path']}/{$interface}_ip", $curwanip);
+}
+
+link_interface_to_vips($interface, "update");
+
+unset($gre);
+$gre = link_interface_to_gre($interface);
+if (!empty($gre)) {
+ array_walk($gre, 'interface_gre_configure');
+}
+
+unset($gif);
+$gif = link_interface_to_gif($interface);
+if (!empty($gif)) {
+ array_walk($gif, 'interface_gif_configure');
+}
+
+$grouptmp = link_interface_to_group($interface);
+if (!empty($grouptmp)) {
+ array_walk($grouptmp, 'interface_group_add_member');
+}
+
+unset($bridgetmp);
+$bridgetmp = link_interface_to_bridge($interface);
+if (!empty($bridgetmp)) {
+ interface_bridge_add_member($bridgetmp, $interface_real);
+}
+
+// Do not process while booting
+if (platform_booting()) {
+ return;
+}
+
+/* make new hosts file */
+system_hosts_generate();
+
+/* check tunnelled IPv6 interface tracking */
+switch ($config['interfaces'][$interface]['ipaddrv6']) {
+ case "6to4":
+ interface_6to4_configure($interface, $config['interfaces'][$interface]);
+ break;
+ case "6rd":
+ interface_6rd_configure($interface, $config['interfaces'][$interface]);
+ break;
+ case "dhcp6":
+ if (isset($config['interfaces'][$interface]['dhcp6usev4iface'])) {
+ interface_dhcpv6_configure($interface, $config['interfaces'][$interface]);
+ }
+ break;
+}
+
+/* Check Gif tunnels */
+if (!empty($gif)) {
+ foreach ($gif as $giftun) {
+ $confif = convert_real_interface_to_friendly_interface_name($giftun['gifif']);
+ if (!empty($confif)) {
+ interface_configure($confif);
+ system_routing_configure($confif);
+ }
+ }
+}
+if (!empty($gre)) {
+ foreach ($gre as $gretun) {
+ $confif = convert_real_interface_to_friendly_interface_name($gretun['greif']);
+ if (!empty($confif)) {
+ interface_configure($confif);
+ system_routing_configure($confif);
+ }
+ }
+}
+
+/*
+ * We need to force sync VPNs on such even when the IP is the same for dynamic interfaces.
+ * Even with the same IP the VPN software is unhappy with the IP disappearing, and we
+ * could be failing back in which case we need to switch IPs back anyhow.
+ */
+if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
+ /* IP changed, kill states accordingly */
+ if ($curwanip != $oldip) {
+ log_error("IP has changed, killing states on former IP $oldip.");
+ pfSense_kill_states($oldip);
+ if (isset($config['system']['ip_change_kill_states'])) {
+ /* hidden config option to wipe all states if needed */
+ log_error("Killing all states post-IP change.");
+ filter_flush_state_table();
+ }
+ }
+
+ /*
+ * Some services (e.g. dyndns, see ticket #4066) depend on
+ * filter_configure() to be called before, otherwise pass out
+ * route-to rules have the old ip set in 'from' and connection
+ * do not go through correct link
+ */
+ filter_configure_sync();
+
+ /* reconfigure static routes (kernel may have deleted them) */
+ system_routing_configure($interface);
+
+ /* reconfigure our gateway monitor */
+ setup_gateways_monitor();
+
+ /* reload unbound */
+ services_unbound_configure();
+
+ if (is_ipaddr($curwanip)) {
+ @file_put_contents("{$g['vardb_path']}/{$interface}_cacheip", $curwanip);
+ }
+
+ /* perform RFC 2136 DNS update */
+ services_dnsupdate_process($interface);
+
+ /* signal dyndns update */
+ services_dyndns_configure($interface);
+
+ /* reconfigure IPsec tunnels */
+ vpn_ipsec_force_reload($interface);
+
+ /* start OpenVPN server & clients */
+ if (substr($interface_real, 0, 4) != "ovpn") {
+ openvpn_resync_all($interface);
+ }
+
+ /* reload graphing functions */
+ enable_rrd_graphing();
+
+ /* reload igmpproxy */
+ services_igmpproxy_configure();
+
+ /* restart snmp */
+ services_snmpd_configure();
+
+ restart_packages();
+} else {
+ /* signal filter reload */
+ filter_configure();
+}
+
+?>
diff --git a/src/etc/rc.newwanipv6 b/src/etc/rc.newwanipv6
new file mode 100755
index 0000000..1030d96
--- /dev/null
+++ b/src/etc/rc.newwanipv6
@@ -0,0 +1,204 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.newwanipv6
+ Copyright (C) 2006 Scott Ullrich (sullrich@gmail.com)
+ part of pfSense (https://www.pfsense.org)
+
+ Originally part of m0n0wall (http://m0n0.ch)
+ Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+require_once("openvpn.inc");
+require_once("IPv6.inc");
+require_once("services.inc");
+require_once("rrd.inc");
+
+function restart_packages() {
+ global $oldipv6, $curwanipv6, $g;
+
+ /* restart packages */
+ system_ntp_configure(false);
+ mwexec_bg("/usr/local/sbin/ntpdate_sync_once.sh", true);
+ log_error("{$g['product_name']} package system has detected an IP change or dynamic WAN reconnection - $oldipv6 -> $curwanipv6 - Restarting packages.");
+ send_event("service reload packages");
+}
+
+/* Interface IP address has changed */
+if (isset($_GET['interface'])) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = trim($argv[1], " \n\t");
+}
+
+log_error("rc.newwanipv6: Info: starting on {$argument}.");
+
+if (empty($argument)) {
+ $interface = "wan";
+ $interface_real = get_real_interface($interface, "inet6");
+ $curwanipv6 = get_interface_ipv6($interface, true);
+} else {
+ $interface_real = $argument;
+ $interface = convert_real_interface_to_friendly_interface_name($interface_real);
+ $curwanipv6 = get_interface_ipv6($interface, true);
+}
+
+$interface_descr = convert_friendly_interface_to_friendly_descr($interface);
+
+if (empty($interface)) {
+ filter_configure();
+ // restart_packages();
+ return;
+}
+
+//Do not process while booting
+if (platform_booting() && $config['interfaces'][$interface]['ipaddrv6'] != "dhcp6") {
+ return;
+}
+
+/*
+ * NOTE: Take care of openvpn and similar if you generate the event to reconfigure an interface.
+ * i.e. OpenVPN might be in tap mode and not have an ip.
+ */
+if ((empty($curwanipv6) || !is_ipaddrv6($curwanipv6)) && substr($interface_real, 0, 4) != "ovpn") {
+ log_error("rc.newwanipv6: Failed to update {$interface_descr}[{$interface}] IPv6, restarting...");
+ // send_event("interface reconfigure {$interface}");
+ return;
+}
+
+if (isset($_GET['dmips'])) {
+ $new_domain_name_servers = $_GET['dmips'];
+} else {
+ $new_domain_name_servers = getenv("new_domain_name_servers");
+}
+
+if (!empty($new_domain_name_servers)) {
+ $name_servers = explode(" ", $new_domain_name_servers);
+ $valid_ns = array();
+ foreach ($name_servers as $ns) {
+ if (is_ipaddrv6(trim($ns))) {
+ $valid_ns[] = trim($ns);
+ }
+ }
+
+ if (count($valid_ns > 0)) {
+ file_put_contents("{$g['varetc_path']}/nameserver_v6{$interface}", implode("\n", $valid_ns));
+ }
+}
+if (isset($_GET['dmnames'])) {
+ $new_domain_name = $_GET['dmnames'];
+} else {
+ $new_domain_name = getenv("new_domain_name");
+}
+
+if (!empty($new_domain_name)) {
+ file_put_contents("{$g['varetc_path']}/searchdomain_v6{$interface}", $new_domain_name);
+}
+
+/* write current WAN IPv6 to file */
+if (is_ipaddrv6($curwanipv6)) {
+ @file_put_contents("{$g['vardb_path']}/{$interface}_ipv6", $curwanipv6);
+}
+
+log_error("rc.newwanipv6: on (IP address: {$curwanipv6}) (interface: {$interface}) (real interface: {$interface_real}).");
+
+$oldipv6 = '';
+if (file_exists("{$g['vardb_path']}/{$interface}_cacheipv6")) {
+ $oldipv6 = file_get_contents("{$g['vardb_path']}/{$interface}_cacheipv6");
+}
+
+$grouptmp = link_interface_to_group($interface);
+if (!empty($grouptmp)) {
+ array_walk($grouptmp, 'interface_group_add_member');
+}
+
+link_interface_to_track6($interface, "update");
+
+/* regenerate resolv.conf if DNS overrides are allowed */
+system_resolvconf_generate(true);
+
+/* reconfigure static routes (kernel may have deleted them) */
+system_routing_configure($interface);
+
+/* reconfigure our gateway monitor */
+setup_gateways_monitor();
+
+/* signal filter reload */
+filter_configure();
+
+if (empty($oldipv6) || is_ipaddrv6($oldipv6)) {
+ if ($curwanipv6 == $oldipv6) {
+ // Still need to sync VPNs on PPPoE and such, as even with the same IP the VPN software is unhappy with the IP disappearing.
+ if (in_array($config['interfaces'][$interface]['ipaddrv6'], array('pppoe', 'pptp', 'ppp'))) {
+ /* reconfigure IPsec tunnels */
+ vpn_ipsec_force_reload($interface);
+
+ /* start OpenVPN server & clients */
+ if (substr($interface_real, 0, 4) != "ovpn") {
+ openvpn_resync_all($interface);
+ }
+ }
+ return;
+ } else if (does_interface_exist($interface_real) && !empty($oldipv6)) {
+ mwexec("/sbin/ifconfig {$interface_real} inet6 {$oldipv6} delete");
+ }
+
+ file_put_contents("{$g['vardb_path']}/{$interface}_cacheipv6", $curwanipv6);
+}
+
+/* reload unbound */
+services_unbound_configure();
+
+/* perform RFC 2136 DNS update */
+services_dnsupdate_process($interface);
+
+/* signal dyndns update */
+services_dyndns_configure($interface);
+
+/* reconfigure IPsec tunnels */
+vpn_ipsec_force_reload($interface);
+
+/* start OpenVPN server & clients */
+if (substr($interface_real, 0, 4) != "ovpn") {
+ openvpn_resync_all($interface);
+}
+
+/* reload graphing functions */
+enable_rrd_graphing();
+
+/* reload igmpproxy */
+services_igmpproxy_configure();
+
+restart_packages();
+
+?>
diff --git a/src/etc/rc.notify_message b/src/etc/rc.notify_message
new file mode 100755
index 0000000..fec1949
--- /dev/null
+++ b/src/etc/rc.notify_message
@@ -0,0 +1,64 @@
+#!/usr/local/bin/php-cgi
+<?php
+/*
+ rc.notify_message
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("notices.inc");
+
+$arguments = getopt("egm:");
+
+$send_email = false;
+$send_growl = false;
+$message = "";
+
+foreach ($arguments as $item => $arg) {
+ switch ($item) {
+ case "e":
+ $send_email = true;
+ break;
+ case "g":
+ $send_growl = true;
+ break;
+ case "m":
+ $message = $arg;
+ break;
+ }
+}
+
+if ($message) {
+ if ($send_email) {
+ notify_via_smtp($message);
+ }
+ if ($send_growl) {
+ notify_via_growl($message);
+ }
+}
+
+?>
diff --git a/src/etc/rc.ntpdate b/src/etc/rc.ntpdate
new file mode 100755
index 0000000..4bdc647
--- /dev/null
+++ b/src/etc/rc.ntpdate
@@ -0,0 +1,39 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id: */
+/*
+ rc.ntpdate
+ part of m0n0wall (http://m0n0.ch/wall)
+ Copyright (C) 2003-2004 Scott Ullrich <sullrich@gmail.com>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("filter.inc");
+ require_once("shaper.inc");
+
+ system_ntp_configure();
+?>
diff --git a/src/etc/rc.openvpn b/src/etc/rc.openvpn
new file mode 100755
index 0000000..cda8067
--- /dev/null
+++ b/src/etc/rc.openvpn
@@ -0,0 +1,132 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.openvpn
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2007 Manuel Kasper <mk@neon1.net>.
+ Copyright (C) 2009 Seth Mos <seth.mos@dds.nl>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+require_once("util.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("gwlb.inc");
+require_once("openvpn.inc");
+
+function openvpn_resync_if_needed ($mode, $ovpn_settings, $interface) {
+ global $g, $config;
+
+ $resync_needed = true;
+ if (isset($ovpn_settings['disable'])) {
+ $resync_needed = false;
+ } else {
+ if (!empty($interface)) {
+ $mode_id = $mode . $ovpn_settings['vpnid'];
+ $fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
+ if (file_exists($fpath)) {
+ /* Compare the interface currently used by the VPN with the interface that should be used.
+ If the VPN should stay on the same interface, do not resync */
+ if (trim(file_get_contents($fpath), " \t\n") == get_failover_interface($ovpn_settings['interface'])) {
+ $resync_needed = false;
+ }
+ }
+ }
+ }
+ if ($resync_needed == true) {
+ log_error("OpenVPN: Resync " . $mode_id . " " . $ovpn_settings['description']);
+ openvpn_resync($mode, $ovpn_settings);
+ }
+}
+
+/* make sure to wait until the boot scripts have finished */
+if (file_exists("{$g['varrun_path']}/booting")) {
+ return;
+}
+
+/* Input argument is a comma-separated list of gateway names, blank or "all". */
+if (isset($_GET['interface'])) {
+ $argument = $_GET['interface'];
+} else {
+ $argument = trim($argv[1], " \n");
+}
+
+if ((is_array($config['openvpn']['openvpn-server']) && count($config['openvpn']['openvpn-server'])) ||
+ (is_array($config['openvpn']['openvpn-client']) && count($config['openvpn']['openvpn-client']))) {
+ if (empty($argument) || $argument == "all") {
+ $argument = "all";
+ $log_text = "all";
+ } else {
+ $log_text = "endpoints that may use " . $argument;
+ }
+ log_error("OpenVPN: One or more OpenVPN tunnel endpoints may have changed its IP. Reloading " . $log_text . ".");
+} else {
+ return;
+}
+
+$openvpnlck = try_lock('openvpn', 10);
+if (!$openvpnlck) {
+ log_error(gettext("Could not obtain openvpn lock for executing rc.openvpn for more than 10 seconds continuing..."));
+ unlock_force('openvpn');
+ $openvpnlck = lock('openvpn', LOCK_EX);
+}
+
+$arg_array = explode(",", $argument);
+foreach ($arg_array as $arg_element) {
+ $gwgroups = array();
+ if ($arg_element == "all") {
+ $interface = "";
+ } else {
+ // e.g. $arg_element = "WANGW", $interface = "wan"
+ $interface = lookup_gateway_interface_by_name($arg_element);
+ if (empty($interface)) {
+ $interface = $arg_element;
+ } else {
+ // e.g. $arg_element = "WANGW", $gwgroups = array of gateway groups that use "wan"
+ $gwgroups = gateway_is_gwgroup_member($arg_element);
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-server'])) {
+ foreach ($config['openvpn']['openvpn-server'] as &$server) {
+ if ($server['interface'] == $interface || empty($interface) || (!empty($gwgroups) && in_array($server['interface'], $gwgroups))) {
+ openvpn_resync_if_needed('server', $server, $interface);
+ }
+ }
+ }
+
+ if (is_array($config['openvpn']['openvpn-client'])) {
+ foreach ($config['openvpn']['openvpn-client'] as &$client) {
+ if ($client['interface'] == $interface || empty($interface) || (!empty($gwgroups) && in_array($client['interface'], $gwgroups))) {
+ openvpn_resync_if_needed('client', $client, $interface);
+ }
+ }
+ }
+}
+
+unlock($openvpnlck);
+?>
diff --git a/src/etc/rc.packages b/src/etc/rc.packages
new file mode 100755
index 0000000..cdca880
--- /dev/null
+++ b/src/etc/rc.packages
@@ -0,0 +1,88 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.packages
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("captiveportal.inc");
+require_once("pkg-utils.inc");
+require_once("pfsense-utils.inc");
+
+function usage() {
+ print "Usage: rc.packages PKG_NAME (POST-INSTALL|DEINSTALL|POST-DEINSTALL)\n";
+ exit(1);
+}
+
+$pkg_interface = "console";
+
+/* Keep old behavior: with no params, sync all and exit */
+if ($argc == 1) {
+ resync_all_package_configs(true);
+ exit;
+}
+
+$pkg = '';
+$when = '';
+
+if (isset($_GET['pkg'])) {
+ $pkg = $_GET['pkg'];
+} else {
+ $pkg = $argv[1];
+}
+
+if (isset($_GET['when'])) {
+ $when = strtolower($_GET['when']);
+} else {
+ $when = strtolower($argv[2]);
+}
+
+if ($pkg == '' || $when == '') {
+ print "Error: invalid parameters\n";
+ usage();
+}
+
+/* Remove pkg_prefix from pkg name */
+pkg_remove_prefix($pkg);
+
+switch ($when) {
+case "post-install":
+ install_package_xml($pkg);
+ break;
+case "deinstall":
+case "post-deinstall":
+ delete_package_xml($pkg, $when);
+ break;
+default:
+ usage();
+}
+
+?>
diff --git a/src/etc/rc.php-fpm_restart b/src/etc/rc.php-fpm_restart
new file mode 100755
index 0000000..6ce04c6
--- /dev/null
+++ b/src/etc/rc.php-fpm_restart
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+echo ">>> Killing php-fpm"
+/bin/pkill -F /var/run/php-fpm.pid
+sleep 2
+
+# Run the php.ini setup file and populate
+# /usr/local/etc/php.ini and /usr/local/lib/php.ini
+/etc/rc.conf_mount_rw
+/etc/rc.php_ini_setup 2>/tmp/php_errors.txt
+/bin/rm -f /var/run/php-fpm.pid 2>/dev/null
+/bin/rm -f /var/run/php-fpm.socket 2>/dev/null
+/etc/rc.conf_mount_ro
+echo ">>> Restarting php-fpm" | /usr/bin/logger -p daemon.info -i -t rc.php-fpm_restart
+echo ">>> Starting php-fpm"
+/usr/local/sbin/php-fpm -c /usr/local/lib/php.ini -y /usr/local/lib/php-fpm.conf -RD 2>&1 >/dev/null
+
diff --git a/src/etc/rc.php_ini_setup b/src/etc/rc.php_ini_setup
new file mode 100755
index 0000000..0013b58
--- /dev/null
+++ b/src/etc/rc.php_ini_setup
@@ -0,0 +1,417 @@
+#!/bin/sh
+#
+# rc.php_ini_setup
+# Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# Set our operating platform
+PLATFORM=`/bin/cat /etc/platform`
+MIN_REALMEM_FOR_OPCACHE=512
+
+if [ -d /usr/local/lib/php/20121212 ]; then
+ EXTENSIONSDIR="/usr/local/lib/php/20121212/"
+elif [ -d /usr/local/lib/php/20090626 ]; then
+ EXTENSIONSDIR="/usr/local/lib/php/20090626/"
+else
+ EXTENSIONSDIR="/usr/local/lib/php/20060613/"
+fi
+
+# Grab amount of memory that is detected
+if [ -f /var/log/dmesg.boot ]; then
+ AVAILMEM=`/bin/cat /var/log/dmesg.boot |/usr/bin/awk '/avail memory/ { memory=($4 / 1048576); printf("%0.0f\n", memory); exit}'`
+else
+ AVAILMEM=`/sbin/dmesg -a |/usr/bin/awk '/avail memory/ { memory=($4 / 1048576); printf("%0.0f\n", memory); exit}'`
+fi
+
+if [ -z "$AVAILMEM" ]; then
+ MEM=`/sbin/sysctl hw.physmem | cut -d':' -f2`
+ AVAILMEM=`/bin/expr $MEM / 1048576`
+fi
+
+
+# Get amount of ram installed on this system
+REALMEM=`/sbin/sysctl hw.realmem | /usr/bin/awk '{print $2/1048576}' | /usr/bin/awk -F '.' '{print $1}'`
+export REALMEM
+export LOWMEM
+
+if [ ${REALMEM} -lt $MIN_REALMEM_FOR_OPCACHE ]; then
+ LOWMEM="TRUE"
+ echo ">>> Under $MIN_REALMEM_FOR_OPCACHE megabytes of ram detected. Not enabling opcache"
+ echo ">>> Under $MIN_REALMEM_FOR_OPCACHE megabytes of ram detected. Not enabling opcache" | /usr/bin/logger -p daemon.info -i -t rc.php_ini_setup
+else
+
+ # Calculate opcache memory size according
+ # to detected memory values
+ if [ "$AVAILMEM" -gt "135" ]; then
+ OPCACHEMEMSIZE="10"
+ fi
+ if [ "$AVAILMEM" -gt "256" ]; then
+ OPCACHEMEMSIZE="20"
+ fi
+ if [ "$AVAILMEM" -gt "384" ]; then
+ OPCACHEMEMSIZE="25"
+ fi
+ if [ "$AVAILMEM" -gt "512" ]; then
+ OPCACHEMEMSIZE="30"
+ fi
+ if [ "$AVAILMEM" -gt "784" ]; then
+ OPCACHEMEMSIZE="50"
+ fi
+fi
+
+# Set upload directory
+if [ "$PLATFORM" = "nanobsd" ]; then
+ UPLOADTMPDIR=`/usr/bin/grep upload_path /etc/inc/globals.inc | /usr/bin/cut -d'"' -f4`
+else
+ UPLOADTMPDIR="/tmp"
+fi
+
+# Define php modules. Do not add .so, it will
+# be done automatically by the script below.
+PHPMODULES="standard"
+if [ "$LOWMEM" != "TRUE" ]; then
+ PHPMODULES="$PHPMODULES opcache"
+fi
+# Config read/write
+PHPMODULES="$PHPMODULES xml libxml dom"
+PHPMODULES="$PHPMODULES SimpleXML xmlreader xmlwriter"
+# Downloading via HTTP/FTP (pkg mgr, etc)
+PHPMODULES="$PHPMODULES curl date"
+# Internationalization
+PHPMODULES="$PHPMODULES gettext"
+# User manager
+PHPMODULES="$PHPMODULES ldap openssl pcntl"
+PHPMODULES="$PHPMODULES hash"
+PHPMODULES="$PHPMODULES mcrypt"
+# Regexs, PERL style!
+PHPMODULES="$PHPMODULES pcre"
+# The mighty posix!
+PHPMODULES="$PHPMODULES posix"
+PHPMODULES="$PHPMODULES readline"
+# Login sessions
+PHPMODULES="$PHPMODULES session"
+# Extra sanity seatbelts
+PHPMODULES="$PHPMODULES suhosin"
+# Firewall rules edit
+PHPMODULES="$PHPMODULES ctype"
+# firewall_rules_edit.php
+PHPMODULES="$PHPMODULES mbstring"
+# Synchronization primitives
+PHPMODULES="$PHPMODULES shmop"
+# Page compression
+PHPMODULES="$PHPMODULES zlib"
+# SQLlite & Database
+PHPMODULES="$PHPMODULES spl"
+PHPMODULES="$PHPMODULES PDO"
+PHPMODULES="$PHPMODULES sqlite3"
+# RADIUS
+PHPMODULES="$PHPMODULES radius"
+# ZeroMQ
+PHPMODULES="$PHPMODULES zmq"
+# SSH2
+PHPMODULES="$PHPMODULES ssh2"
+# pfSense extensions
+PHPMODULES="$PHPMODULES pfSense"
+# json
+PHPMODULES="$PHPMODULES json"
+# bcmath
+PHPMODULES="$PHPMODULES bcmath"
+# filter
+PHPMODULES="$PHPMODULES filter"
+
+PHP_ZEND_MODULES="ioncube_loader"
+PHP_ZEND_MODULES_TS="ioncube_loader_ts"
+
+# Modules previously included.
+# can be turned on by touching
+# /etc/php_dynamodules/$modulename
+# sysvmsg \
+# sysvsem \
+# sysvshm \
+# bcmath \
+# tokenizer \
+# uploadprogress \
+# sockets \
+# Reflection \
+# mysql \
+# bz2 \
+
+# Clear the .ini file to make sure we are clean
+if [ -f /usr/local/etc/php.ini ]; then
+ /bin/rm /usr/local/etc/php.ini
+fi
+if [ -f /usr/local/lib/php.ini ]; then
+ /bin/rm /usr/local/lib/php.ini
+fi
+LOADED_MODULES=`/usr/local/bin/php-cgi -m | /usr/bin/grep -v "\["`
+
+# Fetch the timezone from the XML and set it here. We set it later too in the running scripts
+TIMEZONE=`cat /conf/config.xml | egrep -E '<timezone>(.*?)</timezone>' | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
+
+# Get a loaded module list in the stock php
+# Populate a dummy php.ini to avoid
+# the file being clobbered and the firewall
+# not being able to boot back up.
+/bin/cat >/usr/local/lib/php.ini <<EOF
+; File generated from /etc/rc.php_ini_setup
+output_buffering = "0"
+expose_php = Off
+implicit_flush = true
+magic_quotes_gpc = Off
+max_execution_time = 900
+max_input_time = 1800
+register_argc_argv = On
+register_long_arrays = Off
+variables_order = "GPCS"
+file_uploads = On
+upload_tmp_dir = ${UPLOADTMPDIR}
+upload_max_filesize = 200M
+post_max_size = 200M
+html_errors = Off
+zlib.output_compression = Off
+zlib.output_compression_level = 1
+include_path = ".:/etc/inc:/usr/local/www:/usr/local/captiveportal:/usr/local/pkg"
+display_startup_errors=on
+display_errors=on
+log_errors=on
+error_log=/tmp/PHP_errors.log
+extension_dir=${EXTENSIONSDIR}
+date.timezone="${TIMEZONE}"
+
+; Extensions
+
+EOF
+
+# Copy php.ini file to etc/ too (cli)
+/bin/cp /usr/local/lib/php.ini /usr/local/etc/php.ini
+
+# Ensure directory exists
+if [ ! -d /etc/php_dynamodules ]; then
+ /bin/mkdir /etc/php_dynamodules
+fi
+if [ ! -d /etc/php_dynamodules_zend ]; then
+ /bin/mkdir /etc/php_dynamodules_zend
+fi
+if [ ! -d /etc/php_dynamodules_zend_ts ]; then
+ /bin/mkdir /etc/php_dynamodules_zend_ts
+fi
+
+# Read in dynamodules
+if [ -d /etc/php_dynamodules ]; then
+ DYNA_MODULES=`/bin/ls -Utr /etc/php_dynamodules/`
+ PHPMODULES="$PHPMODULES $DYNA_MODULES"
+fi
+
+# Read in zend modules
+if [ -d /etc/php_dynamodules_zend ]; then
+ DYNA_MODULES=`/bin/ls /etc/php_dynamodules_zend/`
+ PHP_ZEND_MODULES="$PHP_ZEND_MODULES $DYNA_MODULES"
+fi
+
+# Read in zend threaded modules
+if [ -d /etc/php_dynamodules_zend_ts ]; then
+ DYNA_MODULES=`/bin/ls /etc/php_dynamodules_zend_ts/`
+ PHP_ZEND_MODULES_TS="$PHP_ZEND_MODULES_TS $DYNA_MODULES"
+fi
+
+# Loop through and generate modules to load.
+# Take into account modules built into php.
+for EXT in $PHPMODULES; do
+ SHOULDADD="true"
+ # Check to see if module is compiled into php statically
+ for LM in $LOADED_MODULES; do
+ if [ "$EXT" = "$LM" ]; then
+ SHOULDADD="false"
+ fi
+ done
+ if [ "$SHOULDADD" = "true" ]; then
+ # Ensure extension exists before adding.
+ if [ -f "${EXTENSIONSDIR}${EXT}.so" ]; then
+ echo "extension=${EXT}.so" >> /usr/local/lib/php.ini
+ fi
+ fi
+done
+
+# Zend modules
+for EXT in $PHP_ZEND_MODULES; do
+ # Ensure extension exists before adding.
+ if [ -f "${EXTENSIONSDIR}/ioncube/${EXT}.so" ]; then
+ echo "zend_extension=${EXTENSIONSDIR}/ioncube/${EXT}.so" >> /usr/local/lib/php.ini
+ fi
+done
+
+# Zend threaded modules
+for EXT in $PHP_ZEND_MODULES_TS; do
+ # Ensure extension exists before adding.
+ if [ -f "${EXTENSIONSDIR}/ioncube/${EXT}.so" ]; then
+ echo "zend_extension_ts=${EXTENSIONSDIR}/ioncube/${EXT}.so" >> /usr/local/lib/php.ini
+ fi
+done
+
+
+if [ "$LOWMEM" != "TRUE" ]; then
+
+ /bin/cat >>/usr/local/lib/php.ini <<EOF
+
+; opcache Settings
+opcache.enabled="1"
+opcache.enable_cli="0"
+opcache.memory_consumption="${OPCACHEMEMSIZE}"
+
+EOF
+fi
+
+ /bin/cat >>/usr/local/lib/php.ini <<EOF
+
+[suhosin]
+suhosin.get.max_array_depth = 5000
+suhosin.get.max_array_index_length = 256
+suhosin.get.max_vars = 5000
+suhosin.get.max_value_length = 500000
+suhosin.post.max_array_depth = 5000
+suhosin.post.max_array_index_length = 256
+suhosin.post.max_vars = 5000
+suhosin.post.max_value_length = 500000
+suhosin.request.max_array_depth = 5000
+suhosin.request.max_array_index_length = 256
+suhosin.request.max_vars = 5000
+suhosin.request.max_value_length = 500000
+suhosin.memory_limit = 512435456
+
+EOF
+
+
+PHPFPMMAX=3
+if [ $REALMEM -lt 250 ]; then
+ PHPFPMMAX=2
+elif [ ${REALMEM} -gt 1000 ]; then
+ PHPFPMMAX=4
+fi
+
+/bin/cat > /usr/local/lib/php-fpm.conf <<EOF
+
+[global]
+pid = run/php-fpm.pid
+error_log=syslog
+syslog.facility = daemon
+syslog.ident = system
+log_level = error
+daemonize = yes
+events.mechanism = kqueue
+process.max = ${PHPFPMMAX}
+
+[lighty]
+user = root
+group = wheel
+;mode = 0600
+
+listen = /var/run/php-fpm.socket
+listen.owner = root
+listen.group = wheel
+listen.mode = 0600
+
+security.limit_extensions =
+
+; Pass environment variables
+env[PATH] = /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+env[LOGNAME] = root
+
+EOF
+
+if [ $REALMEM -lt 350 ]; then
+ /bin/cat >> /usr/local/lib/php-fpm.conf <<EOF
+
+pm = ondemand
+pm.process_idle_timeout = 5
+pm.max_children = $PHPFPMMAX
+pm.max_requests = 500
+
+EOF
+
+elif [ $REALMEM -gt 1000 ]; then
+ /bin/cat >> /usr/local/lib/php-fpm.conf <<EOF
+
+pm = dynamic
+pm.process_idle_timeout = 5
+pm.max_children = $PHPFPMMAX
+pm.start_servers = 1
+pm.max_requests = 500
+pm.min_spare_servers=1
+pm.max_spare_servers=1
+
+EOF
+else
+
+ /bin/cat >> /usr/local/lib/php-fpm.conf <<EOF
+
+pm = static
+pm.max_children = $PHPFPMMAX
+pm.max_requests = 500
+
+EOF
+
+fi
+
+# Copy php.ini file to etc/ too (cli)
+/bin/cp /usr/local/lib/php.ini /usr/local/etc/php.ini
+
+# Remove old log file if it exists.
+if [ -f /var/run/php_modules_load_errors.txt ]; then
+ /bin/rm /var/run/php_modules_load_errors.txt
+fi
+
+for EXT in $PHPMODULES; do
+ PHPMODULESLC="$PHPMODULESLC `echo "$EXT" | /usr/bin/tr '[:upper:]' '[:lower:]'`"
+done
+
+# Check loaded modules and remove anything that did not load correctly
+LOADED_MODULES=`/usr/local/bin/php-cgi -m | /usr/bin/tr '[:upper:]' '[:lower:]' 2>/dev/null | /usr/bin/grep -v "\["`
+for EXT in $PHPMODULESLC; do
+ SHOULDREMOVE="true"
+ for LM in $LOADED_MODULES; do
+ if [ "$EXT" = "$LM" ]; then
+ SHOULDREMOVE="false"
+ fi
+ done
+ # Handle low memory situations
+ if [ "$LOWMEM" = "TRUE" ]; then
+ if [ "$EXT" = "opcache" ]; then
+ SHOULDREMOVE="true"
+ fi
+ if [ "$EXT" = "xcache" ]; then
+ SHOULDREMOVE="true"
+ fi
+ fi
+ if [ "$SHOULDREMOVE" = "true" ]; then
+ if [ -f "${EXTENSIONSDIR}${EXT}.so" ]; then
+ echo ">>> ${EXT} did not load correctly. Removing from php.ini..." >> /var/run/php_modules_load_errors.txt
+ /bin/cat /usr/local/lib/php.ini | /usr/bin/grep -v $EXT > /tmp/php.ini
+ /bin/rm -f /usr/local/lib/php.ini
+ /bin/mv /tmp/php.ini /usr/local/lib/php.ini
+ fi
+ fi
+done
+
+# Copy php.ini file to etc/ too (cli)
+/bin/cp /usr/local/lib/php.ini /usr/local/etc/php.ini
diff --git a/src/etc/rc.prunecaptiveportal b/src/etc/rc.prunecaptiveportal
new file mode 100755
index 0000000..c4b760a
--- /dev/null
+++ b/src/etc/rc.prunecaptiveportal
@@ -0,0 +1,66 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.prunecaptiveportal
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+/* config.inc retrieves the util.inc and globals.inc */
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("captiveportal.inc");
+
+global $g;
+global $cpzone;
+global $cpzoneid;
+
+$cpzone = str_replace("\n", "", $argv[1]);
+if (!is_array($config['captiveportal'][$cpzone])) {
+ log_error("{$cpzone} is not a valid zone in the configuration!");
+ return;
+}
+$cpzoneid = $config['captiveportal'][$cpzone]['zoneid'];
+
+if (file_exists("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running")) {
+ $stat = stat("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running");
+ if (time() - $stat['mtime'] >= 120) {
+ @unlink("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running");
+ } else {
+ log_error("Skipping CP pruning process because previous/another instance is already running");
+ return;
+ }
+}
+
+@file_put_contents("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running", "");
+captiveportal_prune_old();
+@unlink("{$g['tmp_path']}/.rc.prunecaptiveportal.{$cpzone}.running");
+
+?>
diff --git a/src/etc/rc.reboot b/src/etc/rc.reboot
new file mode 100755
index 0000000..afdc93c
--- /dev/null
+++ b/src/etc/rc.reboot
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# $Id$
+
+if ! /usr/bin/lockf -s -t 30 /tmp/config.lock /usr/bin/true; then
+ echo "Cannot reboot at this moment, a config write operation is in progress, and 30 seconds have passed."
+ exit 1
+fi
+
+sleep 1
+
+# If PLATFORM is pfSense then remove
+# temporary files on shutdown from /tmp/
+PLATFORM=`cat /etc/platform`
+if [ "$PLATFORM" = "pfSense" ]; then
+ rm -rf /tmp/*
+fi
+
+USE_MFS_TMPVAR=`/usr/bin/grep -c use_mfs_tmpvar /cf/conf/config.xml`
+DISK_NAME=`/bin/df /var/db/rrd | /usr/bin/tail -1 | /usr/bin/awk '{print $1;}'`
+DISK_TYPE=`/usr/bin/basename ${DISK_NAME} | /usr/bin/cut -c1-2`
+# If we are not on a full install, or if the full install wants RAM disks, or if the full install _was_ using RAM disks, but isn't for the next boot...
+if [ "${PLATFORM}" != "pfSense" ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = "md" ]; then
+ /etc/rc.backup_rrd.sh
+ /etc/rc.backup_dhcpleases.sh
+fi
+
+sleep 1
+
+SHUTDOWN=/sbin/shutdown
+if [ -f /sbin/shutdown.old ]; then
+ SHUTDOWN=/sbin/shutdown.old
+fi
+
+$SHUTDOWN -r now
diff --git a/src/etc/rc.reload_all b/src/etc/rc.reload_all
new file mode 100755
index 0000000..162553c
--- /dev/null
+++ b/src/etc/rc.reload_all
@@ -0,0 +1,46 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.reload_all
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("ipsec.inc");
+require_once("vpn.inc");
+require_once("captiveportal.inc");
+
+log_error("rc.reload_all: Reloading all configuration settings.");
+reload_all_sync();
+sleep(2);
+log_error("rc.reload_all: Reloading filter configuration.");
+filter_configure_sync();
+
+?>
diff --git a/src/etc/rc.reload_interfaces b/src/etc/rc.reload_interfaces
new file mode 100755
index 0000000..e34588f
--- /dev/null
+++ b/src/etc/rc.reload_interfaces
@@ -0,0 +1,45 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.reload_interfaces
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("openvpn.inc");
+require_once("vpn.inc");
+require_once("captiveportal.inc");
+
+reload_interfaces_sync();
+filter_configure_sync();
+/* XXX: needs fixing */
+//ovpn_config_server("pfreload");
+
+?>
diff --git a/src/etc/rc.resolv_conf_generate b/src/etc/rc.resolv_conf_generate
new file mode 100755
index 0000000..e37203b
--- /dev/null
+++ b/src/etc/rc.resolv_conf_generate
@@ -0,0 +1,36 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ rc.resolv_conf_generate
+ Copyright (C) 2010 Ermal Luçi
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+
+system_resolvconf_generate(true);
+
+?>
diff --git a/src/etc/rc.restart_webgui b/src/etc/rc.restart_webgui
new file mode 100755
index 0000000..7a0bcd3
--- /dev/null
+++ b/src/etc/rc.restart_webgui
@@ -0,0 +1,28 @@
+#!/usr/local/bin/php-cgi -f
+
+<?php
+
+require("config.inc");
+require("functions.inc");
+require("shaper.inc");
+require("captiveportal.inc");
+require_once("rrd.inc");
+
+echo "Restarting webConfigurator...";
+
+sigkillbyname("lighttpd", "KILL");
+
+while (is_process_running("lighttpd")) {
+ echo '.';
+ sleep(1);
+}
+
+system_webgui_start();
+
+captiveportal_init_webgui();
+
+enable_rrd_graphing();
+
+echo " done.\n\n";
+
+?>
diff --git a/src/etc/rc.restore_config_backup b/src/etc/rc.restore_config_backup
new file mode 100755
index 0000000..b64e023
--- /dev/null
+++ b/src/etc/rc.restore_config_backup
@@ -0,0 +1,129 @@
+#!/usr/local/bin/php-cgi -q
+<?php
+require_once('config.inc');
+
+cleanup_backupcache();
+$confvers = get_backups();
+unset($confvers['versions']);
+
+$fp = fopen('php://stdin', 'r');
+
+function print_backup_info($backup_info, $number) {
+ if ($backup_info['time'] != 0) {
+ $date = date(gettext("n/j/y H:i:s"), $backup_info['time']);
+ } else {
+ $date = gettext("Unknown");
+ }
+
+ list($page, $reason) = explode(": ", $backup_info['description'], 2);
+ if (empty($reason)) {
+ $reason = $page;
+ $page = gettext("Unknown Page");
+ }
+
+ echo sprintf("%02d", $number) . ". {$date}\tv{$backup_info['version']}\t{$page}\n";
+ if ($reason) {
+ echo " {$reason}\n";
+ }
+}
+
+function list_backups($which="all", $return=false) {
+ global $confvers;
+
+ if (count($confvers) == 0) {
+ echo gettext("No backups found in the configuration history.");
+ return;
+ }
+
+ for ($c = count($confvers)-1; $c >= 0; $c--) {
+ if (is_numeric($which) && ($c != $which)) {
+ continue;
+ }
+ print_backup_info($confvers[$c], $c+1);
+ echo "\n";
+ }
+}
+
+function choose_backup() {
+ global $fp, $confvers;
+ if (count($confvers) == 0) {
+ echo gettext("No backups found in the configuration history.");
+ return -1;
+ }
+ echo gettext("Which configuration would you like to restore?") . "\n";
+ echo " 1-" . count($confvers) . " : ";
+ $number = strtoupper(chop(fgets($fp)));
+ if (is_numeric($number) && ($number > 0) && ($number <= count($confvers))) {
+ return $number;
+ } else {
+ echo gettext("That is not a valid backup number.\n");
+ return -1;
+ }
+}
+
+function restore_history_backup($number) {
+ global $g, $fp, $confvers;
+ if (is_numeric($number) && ($number > 0) && ($number <= count($confvers))) {
+ $realnumber = $number - 1;
+ echo "\n" . gettext("Is this the backup you wish to restore?") . "\n";
+ list_backups($realnumber);
+ $thisbackup = $confvers[$realnumber];
+ echo gettext("Y/N?") . " : ";
+ $confirm = strtoupper(chop(fgets($fp)));
+ if ($confirm == gettext("Y")) {
+ conf_mount_rw();
+ if (config_restore($g['conf_path'] . '/backup/config-' . $thisbackup['time'] . '.xml') == 0) {
+ echo "\n";
+ echo sprintf(gettext('Successfully reverted to timestamp %1$s with description "%2$s".'), date(gettext("n/j/y H:i:s"), $thisbackup['time']), $thisbackup['description']);
+ echo "\n" . gettext("You may need to reboot the firewall or restart services before the restored configuration is fully active.") . "\n\n";
+ } else {
+ echo gettext("Unable to revert to the selected configuration.") . "\n";
+ }
+ conf_mount_ro();
+ } else {
+ echo gettext("Restore cancelled.") . "\n";
+ }
+ } else {
+ echo gettext("Restore cancelled due to invalid input.") . "\n";
+ }
+}
+
+while (true) {
+
+ echo "\n";
+ echo gettext("Restore Backup from Configuration History") . "\n\n";
+ echo "1) " . gettext("List Backups") . "\n";
+ echo "2) " . gettext("Restore Backup") . "\n";
+ echo "Q) " . gettext("Quit") . "\n";
+ echo "\n\n";
+ echo gettext("Please select an option to continue") . ": ";
+
+ $command = strtolower(chop(fgets($fp)));
+
+ // Make sure we can detect a foreign language "quit" command.
+ if (strtolower($command) == gettext("quit")) {
+ $command = "quit";
+ }
+
+ switch ($command) {
+ case "q":
+ case "quit":
+ echo "\n";
+ fclose($fp);
+ die;
+ break;
+ case "1":
+ list_backups();
+ break;
+ case "2":
+ $number = choose_backup();
+ restore_history_backup($number);
+ fclose($fp);
+ die;
+ break;
+ }
+}
+
+fclose($fp);
+die;
+?>
diff --git a/src/etc/rc.restore_full_backup b/src/etc/rc.restore_full_backup
new file mode 100755
index 0000000..dc44c19
--- /dev/null
+++ b/src/etc/rc.restore_full_backup
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+echo -n "Checking..."
+if [ `tar tzPf $1 /etc/rc 2>/dev/null` ]; then
+ echo " Backup file looks OK."
+ echo "One moment, restoring ${1}..."
+ if [ -f /tmp/do_not_restore_config.xml ]; then
+ EXCLUDE="--exclude /cf/conf/config.xml"
+ rm /tmp/do_not_restore_config.xml
+ else
+ EXCLUDE=""
+ fi
+ tar xzPfU $1 $EXCLUDE -C / 2>/var/etc/restore_log.txt
+ echo "Restore of $1 complete. Rebooting"
+ /sbin/reboot
+else
+ echo " Error."
+ echo "File not found or invalid backup file. Available backups:"
+ ls -lah /root | grep backup | more
+fi
diff --git a/src/etc/rc.savecore b/src/etc/rc.savecore
new file mode 100755
index 0000000..1612a40
--- /dev/null
+++ b/src/etc/rc.savecore
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Based on:
+# FreeBSD: src/etc/rc.d/savecore,v 1.16.2.2.4.1 2010/06/14 02:09:06 kensmith Exp
+
+dumpdev=`/bin/realpath /dev/dumpdev`
+dumpdir='/var/crash'
+
+if [ ! -c "${dumpdev}" ]; then
+ echo "Dump device does not exist. Savecore not run."
+ exit
+fi
+
+if [ ! -d "${dumpdir}" ]; then
+ echo "Dump directory does not exist. Savecore not run."
+ exit
+fi
+
+if savecore -C "${dumpdev}" >/dev/null; then
+ savecore ${dumpdir} ${dumpdev}
+else
+ echo 'No core dumps found.'
+fi
diff --git a/src/etc/rc.savevoucher b/src/etc/rc.savevoucher
new file mode 100755
index 0000000..22e592d
--- /dev/null
+++ b/src/etc/rc.savevoucher
@@ -0,0 +1,40 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2007 Marcel Wiget <mwiget@mac.com>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ /* parse the configuration and include all functions used below */
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("filter.inc");
+ require_once("shaper.inc");
+ require_once("captiveportal.inc");
+ require_once("voucher.inc");
+
+ voucher_save_db_to_config();
+?>
diff --git a/src/etc/rc.shutdown b/src/etc/rc.shutdown
new file mode 100755
index 0000000..aa6468a
--- /dev/null
+++ b/src/etc/rc.shutdown
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+if ! /usr/bin/lockf -s -t 30 /tmp/config.lock /usr/bin/true; then
+ echo "Cannot shutdown at this moment, a config write operation is in progress and 30 seconds have passed."
+ exit -1
+fi
+
+product=`cat /etc/inc/globals.inc | grep product_name | cut -d'"' -f4`
+
+echo
+echo "${product} is now shutting down ..."
+echo
+
+stty status '^T'
+
+# Set shell to ignore SIGINT (2), but not children;
+trap : 2
+
+HOME=/; export HOME
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+export PATH
+
+# If PLATFORM is pfSense then remove
+# temporary files on shutdown from /tmp/
+PLATFORM=`cat /etc/platform`
+if [ "$PLATFORM" = "pfSense" ]; then
+ find -x /tmp/* -type f -exec rm -f {} \; >/dev/null 2>&1
+fi
+
+USE_MFS_TMPVAR=`/usr/bin/grep -c use_mfs_tmpvar /cf/conf/config.xml`
+DISK_NAME=`/bin/df /var/db/rrd | /usr/bin/tail -1 | /usr/bin/awk '{print $1;}'`
+DISK_TYPE=`/usr/bin/basename ${DISK_NAME} | /usr/bin/cut -c1-2`
+# If we are not on a full install, or if the full install wants RAM disks, or if the full install _was_ using RAM disks, but isn't for the next boot...
+if [ "${PLATFORM}" != "pfSense" ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = "md" ]; then
+ /etc/rc.backup_rrd.sh
+ /etc/rc.backup_dhcpleases.sh
+fi
diff --git a/src/etc/rc.start_packages b/src/etc/rc.start_packages
new file mode 100755
index 0000000..3d8bbbc
--- /dev/null
+++ b/src/etc/rc.start_packages
@@ -0,0 +1,88 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.start_packages
+ part of pfSense (https://www.pfsense.org)
+ Copyright (C) 2004 Scott Ullrich
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("filter.inc");
+require_once("shaper.inc");
+require_once("captiveportal.inc");
+require_once("pkg-utils.inc");
+require_once("pfsense-utils.inc");
+require_once("service-utils.inc");
+
+if (file_exists("{$g['tmp_path']}/.rc.start_packages.running")) {
+ $stat = stat("{$g['tmp_path']}/.rc.start_packages.running");
+ if (time() - $stat['mtime'] >= 90) {
+ @unlink("{$g['tmp_path']}/.rc.start_packages.running");
+ } else {
+ log_error("Skipping STARTing packages process because previous/another instance is already running");
+ return;
+ }
+}
+
+@file_put_contents("{$g['tmp_path']}/.rc.start_packages.running", "");
+
+log_error("Restarting/Starting all packages.");
+
+$rcfiles = glob(RCFILEPREFIX . "*.sh");
+if (!$rcfiles) {
+ $rcfiles = array();
+} else {
+ $rcfiles = array_flip($rcfiles);
+ if (!$rcfiles) {
+ $rcfiles = array();
+ }
+}
+
+if (is_array($config['installedpackages']['package'])) {
+ foreach ($config['installedpackages']['package'] as $pkgid => $package) {
+ echo " Starting package {$package['name']}...";
+ sync_package($package['name']);
+ $internal_name = get_package_internal_name($package);
+ start_service($internal_name);
+ unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
+ echo "done.\n";
+ }
+}
+
+$shell = @popen("/bin/sh", "w");
+if ($shell) {
+ foreach ($rcfiles as $rcfile => $number) {
+ echo " Starting {$rcfile}...";
+ fwrite($shell, "{$rcfile} start >>/tmp/bootup_messages 2>&1 &");
+ echo "done.\n";
+ }
+
+ pclose($shell);
+}
+
+@unlink("{$g['tmp_path']}/.rc.start_packages.running");
+?>
diff --git a/src/etc/rc.stop_packages b/src/etc/rc.stop_packages
new file mode 100755
index 0000000..995248a
--- /dev/null
+++ b/src/etc/rc.stop_packages
@@ -0,0 +1,5 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+require_once("pkg-utils.inc");
+stop_packages();
+?>
diff --git a/src/etc/rc.update_alias_url_data b/src/etc/rc.update_alias_url_data
new file mode 100755
index 0000000..fd56b43
--- /dev/null
+++ b/src/etc/rc.update_alias_url_data
@@ -0,0 +1,43 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/* $Id$ */
+/*
+ rc.update_alias_url_data
+ part of pfSense (https://www.pfsense.org)
+
+ Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* parse the configuration and include all functions used below */
+/* config.inc retrieves the util.inc and globals.inc */
+
+require_once("config.inc");
+require_once("functions.inc");
+
+if (update_alias_url_data()) {
+ write_config();
+ send_event("filter reload");
+}
+?>
diff --git a/src/etc/rc.update_bogons.sh b/src/etc/rc.update_bogons.sh
new file mode 100755
index 0000000..85cb7df
--- /dev/null
+++ b/src/etc/rc.update_bogons.sh
@@ -0,0 +1,152 @@
+#!/bin/sh
+
+# Update bogons file
+# Part of the pfSense project
+# https://www.pfsense.org
+
+# Global variables
+proc_error=""
+
+# Download and extract if necessary
+process_url() {
+ local file=$1
+ local url=$2
+ local filename=${url##*/}
+ local ext=${filename#*.}
+
+ /usr/bin/fetch -a -w 600 -T 30 -q -o $file "${url}"
+
+ if [ ! -f $file ]; then
+ echo "Could not download ${url}" | logger
+ proc_error="true"
+ fi
+
+ case "$ext" in
+ tar)
+ mv $file $file.tmp
+ /usr/bin/tar -xf $file.tmp -O > $file 2> /dev/null
+ ;;
+ tar.gz)
+ mv $file $file.tmp
+ /usr/bin/tar -xzf $file.tmp -O > $file 2> /dev/null
+ ;;
+ tgz)
+ mv $file $file.tmp
+ /usr/bin/tar -xzf $file.tmp -O > $file 2> /dev/null
+ ;;
+ tar.bz2)
+ mv $file $file.tmp
+ /usr/bin/tar -xjf $file.tmp -O > $file 2> /dev/null
+ ;;
+ *)
+ ;;
+ esac
+
+ if [ -f $file.tmp ]; then
+ rm $file.tmp
+ fi
+
+ if [ ! -f $file ]; then
+ echo "Could not extract ${filename}" | logger
+ proc_error="true"
+ fi
+}
+
+echo "rc.update_bogons.sh is starting up." | logger
+
+# Sleep for some time, unless an argument is specified.
+if [ "$1" = "" ]; then
+ # Grab a random value
+ value=`od -A n -d -N2 /dev/random | awk '{ print $1 }'`
+ echo "rc.update_bogons.sh is sleeping for $value" | logger
+ sleep $value
+fi
+
+echo "rc.update_bogons.sh is beginning the update cycle." | logger
+
+# Load custom bogon configuration
+if [ -f /var/etc/bogon_custom ]; then
+ . /var/etc/bogon_custom
+fi
+
+# Set default values if not overriden
+v4url=${v4url:-"https://files.pfsense.org/lists/fullbogons-ipv4.txt"}
+v6url=${v6url:-"https://files.pfsense.org/lists/fullbogons-ipv6.txt"}
+v4urlcksum=${v4urlcksum:-"${v4url}.md5"}
+v6urlcksum=${v6urlcksum:-"${v6url}.md5"}
+
+process_url /tmp/bogons "${v4url}"
+process_url /tmp/bogonsv6 "${v6url}"
+
+if [ "$proc_error" != "" ]; then
+ # Relaunch and sleep
+ sh /etc/rc.update_bogons.sh &
+ exit
+fi
+
+BOGON_V4_CKSUM=`/usr/bin/fetch -T 30 -q -o - "${v4urlcksum}" | awk '{ print $4 }'`
+ON_DISK_V4_CKSUM=`md5 /tmp/bogons | awk '{ print $4 }'`
+BOGON_V6_CKSUM=`/usr/bin/fetch -T 30 -q -o - "${v6urlcksum}" | awk '{ print $4 }'`
+ON_DISK_V6_CKSUM=`md5 /tmp/bogonsv6 | awk '{ print $4 }'`
+
+if [ "$BOGON_V4_CKSUM" = "$ON_DISK_V4_CKSUM" ] || [ "$BOGON_V6_CKSUM" = "$ON_DISK_V6_CKSUM" ]; then
+ # At least one of the downloaded checksums matches, so mount RW
+ /etc/rc.conf_mount_rw
+
+ ENTRIES_MAX=`pfctl -s memory | awk '/table-entries/ { print $4 }'`
+
+ if [ "$BOGON_V4_CKSUM" = "$ON_DISK_V4_CKSUM" ]; then
+ ENTRIES_TOT=`pfctl -vvsTables | awk '/Addresses/ {s+=$2}; END {print s}'`
+ ENTRIES_V4=`pfctl -vvsTables | awk '/-\tbogons$/ {getline; print $2}'`
+ LINES_V4=`wc -l /tmp/bogons | awk '{ print $1 }'`
+ if [ $ENTRIES_MAX -gt $((2*ENTRIES_TOT-${ENTRIES_V4:-0}+LINES_V4)) ]; then
+ egrep -v "^192.168.0.0/16|^172.16.0.0/12|^10.0.0.0/8" /tmp/bogons > /etc/bogons
+ RESULT=`/sbin/pfctl -t bogons -T replace -f /etc/bogons 2>&1`
+ echo "$RESULT" | awk '{ print "Bogons V4 file downloaded: " $0 }' | logger
+ else
+ echo "Not updating IPv4 bogons (increase table-entries limit)" | logger
+ fi
+ rm /tmp/bogons
+ else
+ echo "Could not download ${v4url} (checksum mismatch)" | logger
+ checksum_error="true"
+ fi
+
+ if [ "$BOGON_V6_CKSUM" = "$ON_DISK_V6_CKSUM" ]; then
+ BOGONS_V6_TABLE_COUNT=`pfctl -sTables | grep ^bogonsv6$ | wc -l | awk '{ print $1 }'`
+ ENTRIES_TOT=`pfctl -vvsTables | awk '/Addresses/ {s+=$2}; END {print s}'`
+ LINES_V6=`wc -l /tmp/bogonsv6 | awk '{ print $1 }'`
+ if [ $BOGONS_V6_TABLE_COUNT -gt 0 ]; then
+ ENTRIES_V6=`pfctl -vvsTables | awk '/-\tbogonsv6$/ {getline; print $2}'`
+ if [ $ENTRIES_MAX -gt $((2*ENTRIES_TOT-${ENTRIES_V6:-0}+LINES_V6)) ]; then
+ egrep -iv "^fc00::/7" /tmp/bogonsv6 > /etc/bogonsv6
+ RESULT=`/sbin/pfctl -t bogonsv6 -T replace -f /etc/bogonsv6 2>&1`
+ echo "$RESULT" | awk '{ print "Bogons V6 file downloaded: " $0 }' | logger
+ else
+ echo "Not saving or updating IPv6 bogons (increase table-entries limit)" | logger
+ fi
+ else
+ if [ $ENTRIES_MAX -gt $((2*ENTRIES_TOT+LINES_V6)) ]; then
+ egrep -iv "^fc00::/7" /tmp/bogonsv6 > /etc/bogonsv6
+ echo "Bogons V6 file downloaded but not updating IPv6 bogons table because IPv6 Allow is off" | logger
+ else
+ echo "Not saving IPv6 bogons table (IPv6 Allow is off and table-entries limit is potentially too low)" | logger
+ fi
+ fi
+ rm /tmp/bogonsv6
+ else
+ echo "Could not download ${v6url} (checksum mismatch)" | logger
+ checksum_error="true"
+ fi
+
+ # We mounted RW, so switch back to RO
+ /etc/rc.conf_mount_ro
+fi
+
+if [ "$checksum_error" != "" ]; then
+ # Relaunch and sleep
+ sh /etc/rc.update_bogons.sh &
+ exit
+fi
+
+echo "rc.update_bogons.sh is ending the update cycle." | logger
diff --git a/src/etc/rc.update_urltables b/src/etc/rc.update_urltables
new file mode 100755
index 0000000..c4dfeb1
--- /dev/null
+++ b/src/etc/rc.update_urltables
@@ -0,0 +1,60 @@
+#!/usr/local/bin/php-cgi -q
+<?php
+require_once("config.inc");
+require_once("util.inc");
+require_once("pfsense-utils.inc");
+
+if (!is_array($config['aliases']['alias'])) {
+ // No aliases
+ return;
+}
+
+// Gather list of urltable aliases
+$todo = array();
+foreach ($config['aliases']['alias'] as $alias) {
+ if (preg_match('/urltable/i', $alias['type'])) {
+ $tmp = array();
+ $tmp['type'] = $alias['type'];
+ $tmp['name'] = $alias['name'];
+ $tmp['url'] = $alias['url'];
+ $tmp['freq'] = $alias['updatefreq'];
+ $todo[] = $tmp;
+ }
+}
+
+if (count($todo) > 0) {
+ log_error("{$argv[0]}: Starting up.");
+
+ if ($argv[1] != "now") {
+ // Wait a little before updating.
+ $wait = mt_rand(5, 60);
+ log_error("{$argv[0]}: Sleeping for {$wait} seconds.");
+ sleep($wait);
+ }
+
+ log_error("{$argv[0]}: Starting URL table alias updates");
+
+ $filter_reload = false;
+ foreach ($todo as $t) {
+ $r = process_alias_urltable($t['name'], $t['url'], $t['freq']);
+ if ($r == 1) {
+ $result = "";
+ // TODO: Change it when pf supports tables with ports
+ if ($t['type'] == "urltable") {
+ exec("/sbin/pfctl -t " . escapeshellarg($t['name']) . " -T replace -f /var/db/aliastables/" . escapeshellarg($t['name']) . ".txt 2>&1", $result);
+ } else {
+ $filter_reload = true;
+ }
+ log_error("{$argv[0]}: Updated {$t['name']} content from {$t['url']}: {$result[0]}");
+ } elseif ($r == -1) {
+ log_error("{$argv[0]}: {$t['name']} does not need updating.");
+ } else {
+ log_error("{$argv[0]}: ERROR: could not update {$t['name']} content from {$t['url']}");
+ }
+ }
+
+ if ($filter_reload) {
+ send_event("filter reload");
+ }
+}
+?>
diff --git a/src/etc/services b/src/etc/services
new file mode 100644
index 0000000..1f85da0
--- /dev/null
+++ b/src/etc/services
@@ -0,0 +1,4111 @@
+#
+# Network services, Internet style
+#
+# Note that it is presently the policy of IANA to assign a single well-known
+# port number for both TCP and UDP; hence, most entries here have two entries
+# even if the protocol doesn't support UDP operations.
+#
+# The latest IANA port assignments can be gotten from
+#
+# http://www.iana.org/assignments/port-numbers
+#
+# The Well Known Ports are those from 0 through 1023.
+# The Registered Ports are those from 1024 through 49151
+# The Dynamic and/or Private Ports are those from 49152 through 65535
+#
+# Kerberos services are for Kerberos v4, and are unofficial. Sites running
+# v5 should uncomment v5 entries and comment v4 entries.
+#
+# $FreeBSD: src/etc/services,v 1.62.2.12 2003/02/01 16:48:17 schweikh Exp $
+# From: @(#)services 5.8 (Berkeley) 5/9/91
+#
+# WELL KNOWN PORT NUMBERS
+#
+rtmp 1/ddp #Routing Table Maintenance Protocol
+tcpmux 1/tcp #TCP Port Service Multiplexer
+tcpmux 1/udp #TCP Port Service Multiplexer
+nbp 2/ddp #Name Binding Protocol
+compressnet 2/tcp #Management Utility
+compressnet 2/udp #Management Utility
+compressnet 3/tcp #Compression Process
+compressnet 3/udp #Compression Process
+echo 4/ddp #AppleTalk Echo Protocol
+rje 5/tcp #Remote Job Entry
+rje 5/udp #Remote Job Entry
+zip 6/ddp #Zone Information Protocol
+echo 7/tcp
+echo 7/udp
+discard 9/tcp sink null
+discard 9/udp sink null
+systat 11/tcp users #Active Users
+systat 11/udp users #Active Users
+daytime 13/tcp
+daytime 13/udp
+qotd 17/tcp quote #Quote of the Day
+qotd 17/udp quote #Quote of the Day
+msp 18/tcp #Message Send Protocol
+msp 18/udp #Message Send Protocol
+chargen 19/tcp ttytst source #Character Generator
+chargen 19/udp ttytst source #Character Generator
+ftp-data 20/tcp #File Transfer [Default Data]
+ftp-data 20/udp #File Transfer [Default Data]
+ftp 21/tcp #File Transfer [Control]
+ftp 21/udp #File Transfer [Control]
+ssh 22/tcp #Secure Shell Login
+ssh 22/udp #Secure Shell Login
+telnet 23/tcp
+telnet 23/udp
+# 24/tcp any private mail system
+# 24/udp any private mail system
+smtp 25/tcp mail #Simple Mail Transfer
+smtp 25/udp mail #Simple Mail Transfer
+nsw-fe 27/tcp #NSW User System FE
+nsw-fe 27/udp #NSW User System FE
+msg-icp 29/tcp #MSG ICP
+msg-icp 29/udp #MSG ICP
+msg-auth 31/tcp #MSG Authentication
+msg-auth 31/udp #MSG Authentication
+dsp 33/tcp #Display Support Protocol
+dsp 33/udp #Display Support Protocol
+# 35/tcp any private printer server
+# 35/udp any private printer server
+time 37/tcp timserver
+time 37/udp timserver
+rap 38/tcp #Route Access Protocol
+rap 38/udp #Route Access Protocol
+rlp 39/tcp resource #Resource Location Protocol
+rlp 39/udp resource #Resource Location Protocol
+graphics 41/tcp
+graphics 41/udp
+nameserver 42/tcp name #Host Name Server
+nameserver 42/udp name #Host Name Server
+nicname 43/tcp whois
+nicname 43/udp whois
+mpm-flags 44/tcp #MPM FLAGS Protocol
+mpm-flags 44/udp #MPM FLAGS Protocol
+mpm 45/tcp #Message Processing Module [recv]
+mpm 45/udp #Message Processing Module [recv]
+mpm-snd 46/tcp #MPM [default send]
+mpm-snd 46/udp #MPM [default send]
+ni-ftp 47/tcp #NI FTP
+ni-ftp 47/udp #NI FTP
+auditd 48/tcp #Digital Audit Daemon
+auditd 48/udp #Digital Audit Daemon
+tacacs 49/tcp #Login Host Protocol (TACACS)
+tacacs 49/udp #Login Host Protocol (TACACS)
+re-mail-ck 50/tcp #Remote Mail Checking Protocol
+re-mail-ck 50/udp #Remote Mail Checking Protocol
+la-maint 51/tcp #IMP Logical Address Maintenance
+la-maint 51/udp #IMP Logical Address Maintenance
+xns-time 52/tcp #XNS Time Protocol
+xns-time 52/udp #XNS Time Protocol
+domain 53/tcp #Domain Name Server
+domain 53/udp #Domain Name Server
+xns-ch 54/tcp #XNS Clearinghouse
+xns-ch 54/udp #XNS Clearinghouse
+isi-gl 55/tcp #ISI Graphics Language
+isi-gl 55/udp #ISI Graphics Language
+xns-auth 56/tcp #XNS Authentication
+xns-auth 56/udp #XNS Authentication
+mtp 57/tcp # deprecated
+#PROBLEMS!==============================================================
+# 57/tcp any private terminal access
+#PROBLEMS!==============================================================
+# 57/udp any private terminal access
+xns-mail 58/tcp #XNS Mail
+xns-mail 58/udp #XNS Mail
+# 59/tcp any private file service
+# 59/udp any private file service
+ni-mail 61/tcp #NI MAIL
+ni-mail 61/udp #NI MAIL
+acas 62/tcp #ACA Services
+acas 62/udp #ACA Services
+whois++ 63/tcp
+whois++ 63/udp
+covia 64/tcp #Communications Integrator (CI)
+covia 64/udp #Communications Integrator (CI)
+tacacs-ds 65/tcp #TACACS-Database Service
+tacacs-ds 65/udp #TACACS-Database Service
+sql*net 66/tcp #Oracle SQL*NET
+sql*net 66/udp #Oracle SQL*NET
+bootps 67/tcp dhcps #Bootstrap Protocol Server
+bootps 67/udp dhcps #Bootstrap Protocol Server
+bootpc 68/tcp dhcpc #Bootstrap Protocol Client
+bootpc 68/udp dhcpc #Bootstrap Protocol Client
+tftp 69/tcp #Trivial File Transfer
+tftp 69/udp #Trivial File Transfer
+tftp-proxy 6969/udp
+gopher 70/tcp
+gopher 70/udp
+netrjs-1 71/tcp #Remote Job Service
+netrjs-1 71/udp #Remote Job Service
+netrjs-2 72/tcp #Remote Job Service
+netrjs-2 72/udp #Remote Job Service
+netrjs-3 73/tcp #Remote Job Service
+netrjs-3 73/udp #Remote Job Service
+netrjs-4 74/tcp #Remote Job Service
+netrjs-4 74/udp #Remote Job Service
+# 75/tcp any private dial out service
+# 75/udp any private dial out service
+deos 76/tcp #Distributed External Object Store
+deos 76/udp #Distributed External Object Store
+netrjs 77/tcp
+#PROBLEMS!==============================================================
+# 77/tcp any private RJE service
+#PROBLEMS!==============================================================
+# 77/udp any private RJE service
+vettcp 78/tcp
+vettcp 78/udp
+finger 79/tcp
+finger 79/udp
+http 80/tcp www www-http #World Wide Web HTTP
+http 80/udp www www-http #World Wide Web HTTP
+hosts2-ns 81/tcp #HOSTS2 Name Server
+hosts2-ns 81/udp #HOSTS2 Name Server
+xfer 82/tcp #XFER Utility
+xfer 82/udp #XFER Utility
+mit-ml-dev 83/tcp #MIT ML Device
+mit-ml-dev 83/udp #MIT ML Device
+ctf 84/tcp #Common Trace Facility
+ctf 84/udp #Common Trace Facility
+mit-ml-dev 85/tcp #MIT ML Device
+mit-ml-dev 85/udp #MIT ML Device
+mfcobol 86/tcp #Micro Focus Cobol
+mfcobol 86/udp #Micro Focus Cobol
+ttylink 87/tcp
+#PROBLEMS!===========================================================
+# 87/tcp any private terminal link
+#PROBLEMS!===========================================================
+# 87/udp any private terminal link
+kerberos-sec 88/tcp kerberos # krb5 # Kerberos (v5)
+kerberos-sec 88/udp kerberos # krb5 # Kerberos (v5)
+su-mit-tg 89/tcp #SU/MIT Telnet Gateway
+su-mit-tg 89/udp #SU/MIT Telnet Gateway
+dnsix 90/tcp #DNSIX Securit Attribute Token Map
+dnsix 90/udp #DNSIX Securit Attribute Token Map
+mit-dov 91/tcp #MIT Dover Spooler
+mit-dov 91/udp #MIT Dover Spooler
+npp 92/tcp #Network Printing Protocol
+npp 92/udp #Network Printing Protocol
+dcp 93/tcp #Device Control Protocol
+dcp 93/udp #Device Control Protocol
+objcall 94/tcp #Tivoli Object Dispatcher
+objcall 94/udp #Tivoli Object Dispatcher
+supdup 95/tcp
+supdup 95/udp
+dixie 96/tcp #DIXIE Protocol Specification
+dixie 96/udp #DIXIE Protocol Specification
+swift-rvf 97/tcp #Swift Remote Virtural File Protocol
+swift-rvf 97/udp #Swift Remote Virtural File Protocol
+tacnews 98/tcp #TAC News, Unofficial: Red Hat linuxconf
+tacnews 98/udp #TAC News, Unofficial: Red Hat linuxconf
+metagram 99/tcp #Metagram Relay
+metagram 99/udp #Metagram Relay
+newacct 100/tcp #[unauthorized use]
+hostname 101/tcp hostnames #NIC Host Name Server
+hostname 101/udp hostnames #NIC Host Name Server
+iso-tsap 102/tcp tsap #ISO-TSAP Class 0
+iso-tsap 102/udp tsap #ISO-TSAP Class 0
+gppitnp 103/tcp #Genesis Point-to-Point Trans Net
+gppitnp 103/udp #Genesis Point-to-Point Trans Net
+acr-nema 104/tcp #ACR-NEMA Digital Imag. & Comm. 300
+acr-nema 104/udp #ACR-NEMA Digital Imag. & Comm. 300
+csnet-ns 105/tcp cso-ns cso #Mailbox Name Nameserver
+csnet-ns 105/udp cso-ns cso #Mailbox Name Nameserver
+pop3pw 106/tcp 3com-tsmux #Eudora compatible PW changer
+3com-tsmux 106/udp
+rtelnet 107/tcp #Remote Telnet Service
+rtelnet 107/udp #Remote Telnet Service
+snagas 108/tcp #SNA Gateway Access Server
+snagas 108/udp #SNA Gateway Access Server
+pop2 109/tcp postoffice #Post Office Protocol - Version 2
+pop2 109/udp postoffice #Post Office Protocol - Version 2
+pop3 110/tcp #Post Office Protocol - Version 3
+pop3 110/udp #Post Office Protocol - Version 3
+sunrpc 111/tcp rpcbind #SUN Remote Procedure Call
+sunrpc 111/udp rpcbind #SUN Remote Procedure Call
+mcidas 112/tcp #McIDAS Data Transmission Protocol
+mcidas 112/udp #McIDAS Data Transmission Protocol
+auth 113/tcp ident tap #Authentication Service
+auth 113/udp ident tap #Authentication Service
+audionews 114/tcp #Audio News Multicast
+audionews 114/udp #Audio News Multicast
+sftp 115/tcp #Simple File Transfer Protocol
+sftp 115/udp #Simple File Transfer Protocol
+ansanotify 116/tcp #ANSA REX Notify
+ansanotify 116/udp #ANSA REX Notify
+uucp-path 117/tcp #UUCP Path Service
+uucp-path 117/udp #UUCP Path Service
+sqlserv 118/tcp #SQL Services
+sqlserv 118/udp #SQL Services
+nntp 119/tcp usenet #Network News Transfer Protocol
+nntp 119/udp usenet #Network News Transfer Protocol
+cfdptkt 120/tcp
+cfdptkt 120/udp
+erpc 121/tcp #Encore Expedited Remote Pro.Call
+erpc 121/udp #Encore Expedited Remote Pro.Call
+smakynet 122/tcp
+smakynet 122/udp
+ntp 123/tcp #Network Time Protocol
+ntp 123/udp #Network Time Protocol
+ansatrader 124/tcp #ANSA REX Trader
+ansatrader 124/udp #ANSA REX Trader
+locus-map 125/tcp #Locus PC-Interface Net Map Ser
+locus-map 125/udp #Locus PC-Interface Net Map Ser
+unitary 126/tcp #Unisys Unitary Login
+unitary 126/udp #Unisys Unitary Login
+locus-con 127/tcp #Locus PC-Interface Conn Server
+locus-con 127/udp #Locus PC-Interface Conn Server
+gss-xlicen 128/tcp #GSS X License Verification
+gss-xlicen 128/udp #GSS X License Verification
+pwdgen 129/tcp #Password Generator Protocol
+pwdgen 129/udp #Password Generator Protocol
+cisco-fna 130/tcp #cisco FNATIVE
+cisco-fna 130/udp #cisco FNATIVE
+cisco-tna 131/tcp #cisco TNATIVE
+cisco-tna 131/udp #cisco TNATIVE
+cisco-sys 132/tcp #cisco SYSMAINT
+cisco-sys 132/udp #cisco SYSMAINT
+statsrv 133/tcp #Statistics Service
+statsrv 133/udp #Statistics Service
+ingres-net 134/tcp #INGRES-NET Service
+ingres-net 134/udp #INGRES-NET Service
+loc-srv 135/tcp epmap #Location Service
+loc-srv 135/udp epmap #Location Service
+profile 136/tcp #PROFILE Naming System
+profile 136/udp #PROFILE Naming System
+netbios-ns 137/tcp #NETBIOS Name Service
+netbios-ns 137/udp #NETBIOS Name Service
+netbios-dgm 138/tcp #NETBIOS Datagram Service
+netbios-dgm 138/udp #NETBIOS Datagram Service
+netbios-ssn 139/tcp #NETBIOS Session Service
+netbios-ssn 139/udp #NETBIOS Session Service
+emfis-data 140/tcp #EMFIS Data Service
+emfis-data 140/udp #EMFIS Data Service
+emfis-cntl 141/tcp #EMFIS Control Service
+emfis-cntl 141/udp #EMFIS Control Service
+bl-idm 142/tcp #Britton-Lee IDM
+bl-idm 142/udp #Britton-Lee IDM
+imap 143/tcp imap2 imap4 #Interim Mail Access Protocol v2
+imap 143/udp imap2 imap4 #Interim Mail Access Protocol v2
+NeWS 144/tcp # Window System
+NeWS 144/udp # Window System
+#PROBLEMS!==============================================================
+#uma 144/tcp #Universal Management Architecture
+#uma 144/udp #Universal Management Architecture
+#PROBLEMS!==============================================================
+uaac 145/tcp #UAAC Protocol
+uaac 145/udp #UAAC Protocol
+iso-tp0 146/tcp
+iso-tp0 146/udp
+iso-ip 147/tcp
+iso-ip 147/udp
+cronus 148/tcp jargon #CRONUS-SUPPORT
+cronus 148/udp jargon #CRONUS-SUPPORT
+aed-512 149/tcp #AED 512 Emulation Service
+aed-512 149/udp #AED 512 Emulation Service
+sql-net 150/tcp
+sql-net 150/udp
+hems 151/tcp
+hems 151/udp
+bftp 152/tcp #Background File Transfer Program
+bftp 152/udp #Background File Transfer Program
+sgmp 153/tcp
+sgmp 153/udp
+netsc-prod 154/tcp
+netsc-prod 154/udp
+netsc-dev 155/tcp
+netsc-dev 155/udp
+sqlsrv 156/tcp #SQL Service
+sqlsrv 156/udp #SQL Service
+knet-cmp 157/tcp #KNET/VM Command/Message Protocol
+knet-cmp 157/udp #KNET/VM Command/Message Protocol
+pcmail-srv 158/tcp #PCMail Server
+pcmail-srv 158/udp #PCMail Server
+nss-routing 159/tcp
+nss-routing 159/udp
+sgmp-traps 160/tcp
+sgmp-traps 160/udp
+snmp 161/tcp
+snmp 161/udp
+snmptrap 162/tcp snmp-trap
+snmptrap 162/udp snmp-trap
+cmip-man 163/tcp #CMIP/TCP Manager
+cmip-man 163/udp #CMIP/TCP Manager
+cmip-agent 164/tcp #CMIP/TCP Agent
+smip-agent 164/udp #CMIP/TCP Agent
+xns-courier 165/tcp #Xerox
+xns-courier 165/udp #Xerox
+s-net 166/tcp #Sirius Systems
+s-net 166/udp #Sirius Systems
+namp 167/tcp
+namp 167/udp
+rsvd 168/tcp
+rsvd 168/udp
+send 169/tcp
+send 169/udp
+print-srv 170/tcp #Network PostScript
+print-srv 170/udp #Network PostScript
+multiplex 171/tcp #Network Innovations Multiplex
+multiplex 171/udp #Network Innovations Multiplex
+cl/1 172/tcp #Network Innovations CL/1
+cl/1 172/udp #Network Innovations CL/1
+xyplex-mux 173/tcp
+xyplex-mux 173/udp
+mailq 174/tcp
+mailq 174/udp
+vmnet 175/tcp
+vmnet 175/udp
+genrad-mux 176/tcp
+genrad-mux 176/udp
+xdmcp 177/tcp #X Display Manager Control Protocol
+xdmcp 177/udp #X Display Manager Control Protocol
+NextStep 178/tcp nextstep NeXTStep #NextStep Window Server
+NextStep 178/udp nextstep NeXTStep #NextStep Window Server
+bgp 179/tcp #Border Gateway Protocol
+bgp 179/udp #Border Gateway Protocol
+ris 180/tcp #Intergraph
+ris 180/udp #Intergraph
+unify 181/tcp
+unify 181/udp
+audit 182/tcp #Unisys Audit SITP
+audit 182/udp #Unisys Audit SITP
+ocbinder 183/tcp
+ocbinder 183/udp
+ocserver 184/tcp
+ocserver 184/udp
+remote-kis 185/tcp
+remote-kis 185/udp
+kis 186/tcp #KIS Protocol
+kis 186/udp #KIS Protocol
+aci 187/tcp #Application Communication Interface
+aci 187/udp #Application Communication Interface
+mumps 188/tcp #Plus Five's MUMPS
+mumps 188/udp #Plus Five's MUMPS
+qft 189/tcp #Queued File Transport
+qft 189/udp #Queued File Transport
+gacp 190/tcp #Gateway Access Control Protocol
+gacp 190/udp cacp #Gateway Access Control Protocol
+prospero 191/tcp #Prospero Directory Service
+prospero 191/udp #Prospero Directory Service
+osu-nms 192/tcp #OSU Network Monitoring System
+osu-nms 192/udp #OSU Network Monitoring System
+srmp 193/tcp #Spider Remote Monitoring Protocol
+srmp 193/udp #Spider Remote Monitoring Protocol
+irc 194/tcp #Internet Relay Chat Protocol
+irc 194/udp #Internet Relay Chat Protocol
+dn6-nlm-aud 195/tcp #DNSIX Network Level Module Audit
+dn6-nlm-aud 195/udp #DNSIX Network Level Module Audit
+dn6-smm-red 196/tcp #DNSIX Session Mgt Module Audit Redir
+dn6-smm-red 196/udp #DNSIX Session Mgt Module Audit Redir
+dls 197/tcp #Directory Location Service
+dls 197/udp #Directory Location Service
+dls-mon 198/tcp #Directory Location Service Monitor
+dls-mon 198/udp #Directory Location Service Monitor
+smux 199/tcp
+smux 199/udp
+src 200/tcp #IBM System Resource Controller
+src 200/udp #IBM System Resource Controller
+at-rtmp 201/tcp #AppleTalk Routing Maintenance
+at-rtmp 201/udp #AppleTalk Routing Maintenance
+at-nbp 202/tcp #AppleTalk Name Binding
+at-nbp 202/udp #AppleTalk Name Binding
+at-3 203/tcp #AppleTalk Unused
+at-3 203/udp #AppleTalk Unused
+at-echo 204/tcp #AppleTalk Echo
+at-echo 204/udp #AppleTalk Echo
+at-5 205/tcp #AppleTalk Unused
+at-5 205/udp #AppleTalk Unused
+at-zis 206/tcp #AppleTalk Zone Information
+at-zis 206/udp #AppleTalk Zone Information
+at-7 207/tcp #AppleTalk Unused
+at-7 207/udp #AppleTalk Unused
+at-8 208/tcp #AppleTalk Unused
+at-8 208/udp #AppleTalk Unused
+qmtp 209/tcp #The Quick Mail Transfer Protocol
+qmtp 209/udp #The Quick Mail Transfer Protocol
+#PROBLEMS!==============================================================
+#tam 209/tcp #Trivial Authenticated Mail Protocol
+#tam 209/udp #Trivial Authenticated Mail Protocol
+#PROBLEMS!==============================================================
+z39.50 210/tcp wais #ANSI Z39.50
+z39.50 210/udp wais #ANSI Z39.50
+914c/g 211/tcp #Texas Instruments 914C/G Terminal
+914c/g 211/udp #Texas Instruments 914C/G Terminal
+anet 212/tcp #ATEXSSTR
+anet 212/udp #ATEXSSTR
+ipx 213/tcp
+ipx 213/udp
+vmpwscs 214/tcp
+vmpwscs 214/udp
+softpc 215/tcp #Insignia Solutions
+softpc 215/udp #Insignia Solutions
+CAIlic 216/tcp atls #Computer Associates Int'l License Server
+CAIlic 216/udp atls #Computer Associates Int'l License Server
+dbase 217/tcp #dBASE Unix
+dbase 217/udp #dBASE Unix
+mpp 218/tcp #Netix Message Posting Protocol
+mpp 218/udp #Netix Message Posting Protocol
+uarps 219/tcp #Unisys ARPs
+uarps 219/udp #Unisys ARPs
+#imap3@220 was never used and never should have been allocated. See PR 46294.
+#imap3 220/tcp #Interactive Mail Access Protocol v3
+#imap3 220/udp #Interactive Mail Access Protocol v3
+fln-spx 221/tcp #Berkeley rlogind with SPX auth
+fln-spx 221/udp #Berkeley rlogind with SPX auth
+rsh-spx 222/tcp #Berkeley rshd with SPX auth
+rsh-spx 222/udp #Berkeley rshd with SPX auth
+cdc 223/tcp #Certificate Distribution Center
+cdc 223/udp #Certificate Distribution Center
+direct 242/tcp
+direct 242/udp
+sur-meas 243/tcp #Survey Measurement
+sur-meas 243/udp #Survey Measurement
+dayna 244/tcp
+dayna 244/udp
+link 245/tcp
+link 245/udp
+dsp3270 246/tcp #Display Systems Protocol
+dsp3270 246/udp #Display Systems Protocol
+subntbcst_tftp 247/tcp #subntbcst_tftp
+subntbcst_tftp 247/udp #subntbcst_tftp
+bhfhs 248/tcp
+bhfhs 248/udp
+# 249-255 reserved
+rap 256/tcp
+rap 256/udp
+set 257/tcp #secure electronic transaction
+set 257/udp #secure electronic transaction
+yak-chat 258/tcp #yak winsock personal chat
+yak-chat 258/udp #yak winsock personal chat
+esro-gen 259/tcp #efficient short remote operations
+esro-gen 259/udp #efficient short remote operations
+openport 260/tcp
+openport 260/udp
+nsiiops 261/tcp #iiop name service over tls/ssl
+nsiiops 261/udp #iiop name service over tls/ssl
+arcisdms 262/tcp
+arcisdms 262/udp
+hdap 263/tcp
+hdap 263/udp
+bgmp 264/tcp
+bgmp 264/udp
+# 265-279 unassigned
+http-mgmt 280/tcp
+http-mgmt 280/udp
+personal-link 281/tcp
+personal-link 281/udp
+cableport-ax 282/tcp #cable port a/x
+cableport-ax 282/udp #cable port a/x
+# 283-307 unassigned
+novastorbakcup 308/tcp #novastor backup
+novastorbakcup 308/udp #novastor backup
+entrusttime 309/tcp
+entrusttime 309/udp
+bhmds 310/tcp
+bhmds 310/udp
+asip-webadmin 311/tcp #appleshare ip webadmin
+asip-webadmin 311/udp #appleshare ip webadmin
+vslmp 312/tcp
+vslmp 312/udp
+magenta-logic 313/tcp
+magenta-logic 313/udp
+opalis-robot 314/tcp
+opalis-robot 314/udp
+dpsi 315/tcp
+dpsi 315/udp
+decauth 316/tcp
+decauth 316/udp
+zannet 317/tcp
+zannet 317/udp
+# 318-320 #unassigned
+pip 321/tcp
+pip 321/udp
+# 322-343 #unassigned
+pdap 344/tcp #Prospero Data Access Protocol
+pdap 344/udp #Prospero Data Access Protocol
+pawserv 345/tcp #Perf Analysis Workbench
+pawserv 345/udp #Perf Analysis Workbench
+zserv 346/tcp #Zebra server
+zserv 346/udp #Zebra server
+fatserv 347/tcp #Fatmen Server
+fatserv 347/udp #Fatmen Server
+csi-sgwp 348/tcp #Cabletron Management Protocol
+csi-sgwp 348/udp #Cabletron Management Protocol
+mftp 349/tcp
+mftp 349/udp
+matip-type-a 350/tcp #MATIP Type A
+matip-type-a 350/udp
+matip-type-b 351/tcp #MATIP Type B
+matip-type-b 351/udp
+bhoetty 351/tcp #unassigned but widespread use
+bhoetty 351/udp #unassigned but widespread use
+dtag-ste-sb 352/tcp #DTAG
+dtag-ste-sb 352/udp #DTAG
+bhoedap4 352/tcp #unassigned but widespread use
+bhoedap4 352/udp #unassigned but widespread use
+ndsauth 353/tcp
+ndsauth 353/udp
+bh611 354/tcp
+bh611 354/udp
+datex-asn 355/tcp
+datex-asn 355/udp
+cloanto-net-1 356/tcp #Cloanto Net 1
+cloanto-net-1 356/udp
+bhevent 357/tcp
+bhevent 357/udp
+shrinkwrap 358/tcp
+shrinkwrap 358/udp
+tenebris_nts 359/tcp #Tenebris Network Trace Service
+tenebris_nts 359/udp #Tenebris Network Trace Service
+scoi2odialog 360/tcp
+scoi2odialog 360/udp
+semantix 361/tcp
+semantix 361/udp
+srssend 362/tcp #SRS Send
+srssend 362/udp #SRS Send
+rsvp_tunnel 363/tcp
+rsvp_tunnel 363/udp
+aurora-cmgr 364/tcp
+aurora-cmgr 364/udp
+dtk 365/tcp #Deception Tool Kit - Fred Cohen <fc@all.net>
+dtk 365/udp #Deception Tool Kit - Fred Cohen <fc@all.net>
+odmr 366/tcp
+odmr 366/udp
+mortgageware 367/tcp
+mortgageware 367/udp
+qbikgdp 368/tcp #QbikGDP
+qbikgdp 368/udp
+rpc2portmap 369/tcp
+rpc2portmap 369/udp
+codaauth2 370/tcp
+codaauth2 370/udp
+clearcase 371/tcp
+clearcase 371/udp
+ulistserv 372/tcp ulistproc #Unix Listserv
+ulistserv 372/udp ulistproc #Unix Listserv
+legent-1 373/tcp #Legent Corporation (now Computer Associates Intl.)
+legent-1 373/udp #Legent Corporation (now Computer Associates Intl.)
+legent-2 374/tcp #Legent Corporation (now Computer Associates Intl.)
+legent-2 374/udp #Legent Corporation (now Computer Associates Intl.)
+hassle 375/tcp
+hassle 375/udp
+nip 376/tcp #Amiga Envoy Network Inquiry Proto
+nip 376/udp #Amiga Envoy Network Inquiry Proto
+tnETOS 377/tcp #NEC Corporation
+tnETOS 377/udp #NEC Corporation
+dsETOS 378/tcp #NEC Corporation
+dsETOS 378/udp #NEC Corporation
+is99c 379/tcp #TIA/EIA/IS-99 modem client
+is99c 379/udp #TIA/EIA/IS-99 modem client
+is99s 380/tcp #TIA/EIA/IS-99 modem server
+is99s 380/udp #TIA/EIA/IS-99 modem server
+hp-collector 381/tcp #hp performance data collector
+hp-collector 381/udp #hp performance data collector
+hp-managed-node 382/tcp #hp performance data managed node
+hp-managed-node 382/udp #hp performance data managed node
+hp-alarm-mgr 383/tcp #hp performance data alarm manager
+hp-alarm-mgr 383/udp #hp performance data alarm manager
+arns 384/tcp #A Remote Network Server System
+arns 384/udp #A Remote Network Server System
+ibm-app 385/tcp #IBM Application
+ibm-app 385/udp #IBM Application
+asa 386/tcp #ASA Message Router Object Def.
+asa 386/udp #ASA Message Router Object Def.
+aurp 387/tcp #Appletalk Update-Based Routing Pro.
+aurp 387/udp #Appletalk Update-Based Routing Pro.
+unidata-ldm 388/tcp #Unidata LDM Version 4
+unidata-ldm 388/udp #Unidata LDM Version 4
+ldap 389/tcp #Lightweight Directory Access Protocol
+ldap 389/udp #Lightweight Directory Access Protocol
+uis 390/tcp
+uis 390/udp
+synotics-relay 391/tcp #SynOptics SNMP Relay Port
+synotics-relay 391/udp #SynOptics SNMP Relay Port
+synotics-broker 392/tcp #SynOptics Port Broker Port
+synotics-broker 392/udp #SynOptics Port Broker Port
+dis 393/tcp #Data Interpretation System
+dis 393/udp #Data Interpretation System
+embl-ndt 394/tcp #EMBL Nucleic Data Transfer
+embl-ndt 394/udp #EMBL Nucleic Data Transfer
+netcp 395/tcp #NETscout Control Protocol
+netcp 395/udp #NETscout Control Protocol
+netware-ip 396/tcp #Novell Netware over IP
+netware-ip 396/udp #Novell Netware over IP
+mptn 397/tcp #Multi Protocol Trans. Net.
+mptn 397/udp #Multi Protocol Trans. Net.
+kryptolan 398/tcp
+kryptolan 398/udp
+iso-tsap-c2 399/tcp #ISO-TSAP Class 2
+iso-tsap-c2 399/udp #ISO-TSAP Class 2
+work-sol 400/tcp #Workstation Solutions
+work-sol 400/udp #Workstation Solutions
+ups 401/tcp #Uninterruptible Power Supply
+ups 401/udp #Uninterruptible Power Supply
+genie 402/tcp #Genie Protocol
+genie 402/udp #Genie Protocol
+decap 403/tcp
+decap 403/udp
+nced 404/tcp
+nced 404/udp
+ncld 405/tcp
+ncld 405/udp
+imsp 406/tcp #Interactive Mail Support Protocol
+imsp 406/udp #Interactive Mail Support Protocol
+timbuktu 407/tcp
+timbuktu 407/udp
+prm-sm 408/tcp #Prospero Resource Manager Sys. Man.
+prm-sm 408/udp #Prospero Resource Manager Sys. Man.
+prm-nm 409/tcp #Prospero Resource Manager Node Man.
+prm-nm 409/udp #Prospero Resource Manager Node Man.
+decladebug 410/tcp #DECLadebug Remote Debug Protocol
+decladebug 410/udp #DECLadebug Remote Debug Protocol
+rmt 411/tcp #Remote MT Protocol
+rmt 411/udp #Remote MT Protocol
+synoptics-trap 412/tcp #Trap Convention Port
+synoptics-trap 412/udp #Trap Convention Port
+smsp 413/tcp
+smsp 413/udp
+infoseek 414/tcp
+infoseek 414/udp
+bnet 415/tcp
+bnet 415/udp
+silverplatter 416/tcp
+silverplatter 416/udp
+onmux 417/tcp
+onmux 417/udp
+hyper-g 418/tcp
+hyper-g 418/udp
+ariel1 419/tcp
+ariel1 419/udp
+smpte 420/tcp
+smpte 420/udp
+ariel2 421/tcp
+ariel2 421/udp
+ariel3 422/tcp
+ariel3 422/udp
+opc-job-start 423/tcp #IBM Operations Planning and Control Start
+opc-job-start 423/udp #IBM Operations Planning and Control Start
+opc-job-track 424/tcp #IBM Operations Planning and Control Track
+opc-job-track 424/udp #IBM Operations Planning and Control Track
+icad-el 425/tcp
+icad-el 425/udp
+smartsdp 426/tcp
+smartsdp 426/udp
+svrloc 427/tcp #Server Location
+svrloc 427/udp #Server Location
+ocs_cmu 428/tcp
+ocs_cmu 428/udp
+ocs_amu 429/tcp
+ocs_amu 429/udp
+utmpsd 430/tcp
+utmpsd 430/udp
+utmpcd 431/tcp
+utmpcd 431/udp
+iasd 432/tcp
+iasd 432/udp
+nnsp 433/tcp
+nnsp 433/udp
+mobileip-agent 434/tcp
+mobileip-agent 434/udp
+mobilip-mn 435/tcp
+mobilip-mn 435/udp
+dna-cml 436/tcp
+dna-cml 436/udp
+comscm 437/tcp
+comscm 437/udp
+dsfgw 438/tcp
+dsfgw 438/udp
+dasp 439/tcp
+dasp 439/udp
+sgcp 440/tcp
+sgcp 440/udp
+decvms-sysmgt 441/tcp
+decvms-sysmgt 441/udp
+cvc_hostd 442/tcp
+cvc_hostd 442/udp
+https 443/tcp
+https 443/udp
+snpp 444/tcp #Simple Network Paging Protocol
+snpp 444/udp #Simple Network Paging Protocol
+# [RFC1568]
+microsoft-ds 445/tcp
+microsoft-ds 445/udp
+ddm-rdb 446/tcp
+ddm-rdb 446/udp
+ddm-dfm 447/tcp
+ddm-dfm 447/udp
+ddm-ssl 448/tcp ddm-byte
+ddm-ssl 448/udp ddm-byte
+as-servermap 449/tcp #AS Server Mapper
+as-servermap 449/udp #AS Server Mapper
+tserver 450/tcp
+tserver 450/udp
+sfs-smp-net 451/tcp #Cray Network Semaphore server
+sfs-smp-net 451/udp #Cray Network Semaphore server
+sfs-config 452/tcp #Cray SFS config server
+sfs-config 452/udp #Cray SFS config server
+creativeserver 453/tcp #CreativeServer
+creativeserver 453/udp #CreativeServer
+contentserver 454/tcp #ContentServer
+contentserver 454/udp #ContentServer
+creativepartnr 455/tcp #CreativePartnr
+creativepartnr 455/udp #CreativePartnr
+macon-tcp 456/tcp
+macon-udp 456/udp
+scohelp 457/tcp
+scohelp 457/udp
+appleqtc 458/tcp #apple quick time
+appleqtc 458/udp #apple quick time
+ampr-rcmd 459/tcp
+ampr-rcmd 459/udp
+skronk 460/tcp
+skronk 460/udp
+datasurfsrv 461/tcp
+datasurfsrv 461/udp
+datasurfsrvsec 462/tcp
+datasurfsrvsec 462/udp
+alpes 463/tcp
+alpes 463/udp
+#
+kpasswd5 464/tcp # Kerberos (v5)
+kpasswd5 464/udp # Kerberos (v5)
+#PROBLEMS!==============================================================
+# IANA has offically assigned these two ports as ``kpasswd''
+#kpasswd 464/tcp # Kerberos (v5)
+#kpasswd 464/udp # Kerberos (v5)
+#PROBLEMS!==============================================================
+smtps 465/tcp #smtp protocol over TLS/SSL (was ssmtp)
+smtps 465/udp #smtp protocol over TLS/SSL (was ssmtp)
+digital-vrc 466/tcp
+digital-vrc 466/udp
+mylex-mapd 467/tcp
+mylex-mapd 467/udp
+photuris 468/tcp
+photuris 468/udp
+rcp 469/tcp #Radio Control Protocol
+rcp 469/udp #Radio Control Protocol
+scx-proxy 470/tcp
+scx-proxy 470/udp
+mondex 471/tcp
+mondex 471/udp
+ljk-login 472/tcp
+ljk-login 472/udp
+hybrid-pop 473/tcp
+hybrid-pop 473/udp
+tn-tl-w1 474/tcp
+tn-tl-w2 474/udp
+tcpnethaspsrv 475/tcp
+tcpnethaspsrv 475/udp
+tn-tl-fd1 476/tcp
+tn-tl-fd1 476/udp
+ss7ns 477/tcp
+ss7ns 477/udp
+spsc 478/tcp
+spsc 478/udp
+iafserver 479/tcp
+iafserver 479/udp
+iafdbase 480/tcp
+iafdbase 480/udp
+ph 481/tcp
+ph 481/udp
+bgs-nsi 482/tcp
+bgs-nsi 482/udp
+ulpnet 483/tcp
+ulpnet 483/udp
+integra-sme 484/tcp #Integra Software Management Environment
+integra-sme 484/udp #Integra Software Management Environment
+powerburst 485/tcp #Air Soft Power Burst
+powerburst 485/udp #Air Soft Power Burst
+avian 486/tcp
+avian 486/udp
+saft 487/tcp #saft Simple Asynchronous File Transfer
+saft 487/udp #saft Simple Asynchronous File Transfer
+gss-http 488/tcp
+gss-http 488/udp
+nest-protocol 489/tcp
+nest-protocol 489/udp
+micom-pfs 490/tcp
+micom-pfs 490/udp
+go-login 491/tcp
+go-login 491/udp
+ticf-1 492/tcp #Transport Independent Convergence for FNA
+ticf-1 492/udp #Transport Independent Convergence for FNA
+ticf-2 493/tcp #Transport Independent Convergence for FNA
+ticf-2 493/udp #Transport Independent Convergence for FNA
+pov-ray 494/tcp
+pov-ray 494/udp
+intecourier 495/tcp
+intecourier 495/udp
+pim-rp-disc 496/tcp
+pim-rp-disc 496/udp
+dantz 497/tcp
+dantz 497/udp
+siam 498/tcp
+siam 498/udp
+iso-ill 499/tcp #ISO ILL Protocol
+iso-ill 499/udp #ISO ILL Protocol
+isakmp 500/tcp
+isakmp 500/udp
+stmf 501/tcp
+stmf 501/udp
+asa-appl-proto 502/tcp
+asa-appl-proto 502/udp
+intrinsa 503/tcp
+intrinsa 503/udp
+citadel 504/tcp
+citadel 504/udp
+mailbox-lm 505/tcp
+mailbox-lm 505/udp
+ohimsrv 506/tcp
+ohimsrv 506/udp
+crs 507/tcp
+crs 507/udp
+xvttp 508/tcp
+xvttp 508/udp
+snare 509/tcp
+snare 509/udp
+fcp 510/tcp #FirstClass Protocol
+fcp 510/udp #FirstClass Protocol
+passgo 511/tcp
+passgo 511/udp
+#
+# Berkeley-specific services
+#
+exec 512/tcp #remote process execution;
+# authentication performed using
+# passwords and UNIX login names
+biff 512/udp comsat #used by mail system to notify users
+# of new mail received; currently
+# receives messages only from
+# processes on the same machine
+login 513/tcp #remote login a la telnet;
+# automatic authentication performed
+# based on priviledged port numbers
+# and distributed data bases which
+# identify "authentication domains"
+who 513/udp whod #maintains data bases showing who's
+# logged in to machines on a local
+# net and the load average of the
+# machine
+shell 514/tcp cmd #like exec, but automatic
+# authentication is performed as for
+# login server
+syslog 514/udp
+printer 515/tcp spooler
+printer 515/udp spooler
+videotex 516/tcp
+videotex 516/udp
+talk 517/tcp #like tenex link, but across
+# machine - unfortunately, doesn't
+# use link protocol (this is actually
+# just a rendezvous port from which a
+# tcp connection is established)
+talk 517/udp #like tenex link, but across
+# machine - unfortunately, doesn't
+# use link protocol (this is actually
+# just a rendezvous port from which a
+# tcp connection is established)
+ntalk 518/tcp
+ntalk 518/udp
+utime 519/tcp unixtime
+utime 519/udp unixtime
+efs 520/tcp #extended file name server
+router 520/udp route routed #local routing process (on site);
+# uses variant of Xerox NS routing
+# information protocol
+ripng 521/tcp
+ripng 521/udp
+ulp 522/tcp
+ulp 522/udp
+ibm-db2 523/tcp
+ibm-db2 523/udp
+ncp 524/tcp
+ncp 524/udp
+timed 525/tcp timeserver
+timed 525/udp timeserver
+tempo 526/tcp newdate
+tempo 526/udp newdate
+stx 527/tcp #Stock IXChange
+stx 527/udp #Stock IXChange
+custix 528/tcp #Customer IXChange
+custix 528/udp #Customer IXChange
+irc-serv 529/tcp
+irc-serv 529/udp
+courier 530/tcp rpc
+courier 530/udp rpc
+conference 531/tcp chat
+conference 531/udp chat
+netnews 532/tcp readnews
+netnews 532/udp readnews
+netwall 533/tcp #for emergency broadcasts
+netwall 533/udp #for emergency broadcasts
+mm-admin 534/tcp #MegaMedia Admin
+mm-admin 534/udp #MegaMedia Admin
+iiop 535/tcp
+iiop 535/udp
+opalis-rdv 536/tcp
+opalis-rdv 536/udp
+nmsp 537/tcp #Networked Media Streaming Protocol
+nmsp 537/udp #Networked Media Streaming Protocol
+gdomap 538/tcp
+gdomap 538/udp
+apertus-ldp 539/tcp #Apertus Technologies Load Determination
+apertus-ldp 539/udp #Apertus Technologies Load Determination
+uucp 540/tcp uucpd
+uucp 540/udp uucpd
+uucp-rlogin 541/tcp
+uucp-rlogin 541/udp
+commerce 542/tcp
+commerce 542/udp
+klogin 543/tcp # Kerberos (v4/v5)
+klogin 543/udp # Kerberos (v4/v5)
+kshell 544/tcp krcmd # Kerberos (v4/v5)
+kshell 544/udp krcmd # Kerberos (v4/v5)
+appleqtcsrvr 545/tcp
+appleqtcsrvr 545/udp
+dhcpv6-client 546/tcp #DHCPv6 Client
+dhcpv6-client 546/udp #DHCPv6 Client
+dhcpv6-server 547/tcp #DHCPv6 Server
+dhcpv6-server 547/udp #DHCPv6 Server
+afpovertcp 548/tcp #AFP over TCP
+afpovertcp 548/udp #AFP over TCP
+idfp 549/tcp
+idfp 549/udp
+new-rwho 550/tcp new-who
+new-rwho 550/udp new-who
+cybercash 551/tcp
+cybercash 551/udp
+deviceshare 552/tcp
+deviceshare 552/udp
+pirp 553/tcp
+pirp 553/udp
+rtsp 554/tcp #Real Time Stream Control Protocol
+rtsp 554/udp #Real Time Stream Control Protocol
+dsf 555/tcp
+dsf 555/udp
+remotefs 556/tcp rfs rfs_server # Brunhoff remote filesystem
+remotefs 556/udp rfs rfs_server # Brunhoff remote filesystem
+openvms-sysipc 557/tcp
+openvms-sysipc 557/udp
+sdnskmp 558/tcp
+sdnskmp 558/udp
+teedtap 559/tcp
+teedtap 559/udp
+rmonitor 560/tcp rmonitord
+rmonitor 560/udp rmonitord
+monitor 561/tcp
+monitor 561/udp
+chshell 562/tcp chcmd
+chshell 562/udp chcmd
+nntps 563/tcp snntp #nntp protocol over TLS/SSL
+nntps 563/udp snntp #nntp protocol over TLS/SSL
+9pfs 564/tcp #plan 9 file service
+9pfs 564/udp #plan 9 file service
+whoami 565/tcp
+whoami 565/udp
+streettalk 566/tcp
+banyan-rpc 567/tcp
+banyan-rpc 567/udp
+ms-shuttle 568/tcp #Microsoft shuttle
+ms-shuttle 568/udp #Microsoft shuttle
+ms-rome 569/tcp #Microsoft rome
+ms-rome 569/udp #Microsoft rome
+meter 570/tcp #demon
+meter 570/udp #demon
+umeter 571/tcp #udemon
+umeter 571/udp #udemon
+sonar 572/tcp
+sonar 572/udp
+banyan-vip 573/tcp
+banyan-vip 573/udp
+ftp-agent 574/tcp #FTP Software Agent System
+ftp-agent 574/udp #FTP Software Agent System
+vemmi 575/tcp
+vemmi 575/udp
+ipcd 576/tcp
+ipcd 576/udp
+vnas 577/tcp
+vnas 577/udp
+ipdd 578/tcp
+ipdd 578/udp
+decbsrv 579/tcp
+decbsrv 579/udp
+sntp-heartbeat 580/tcp
+sntp-heartbeat 580/udp
+bdp 581/tcp #Bundle Discovery Protocol
+bdp 581/udp #Bundle Discovery Protocol
+scc-security 582/tcp
+scc-security 582/udp
+philips-vc 583/tcp #Philips Video-Conferencing
+philips-vc 583/udp #Philips Video-Conferencing
+keyserver 584/tcp
+keyserver 584/udp
+#imap4-ssl@585 never should have been allocated. See PR 46294.
+#imap4-ssl 585/tcp #IMAP4+SSL (use of 585 is not recommended,
+#imap4-ssl 585/udp # use 993 instead)
+password-chg 586/tcp
+password-chg 586/udp
+submission 587/tcp
+submission 587/udp
+cal 588/tcp
+cal 588/udp
+eyelink 589/tcp
+eyelink 589/udp
+tns-cml 590/tcp
+tns-cml 590/udp
+http-alt 591/tcp #FileMaker, Inc. - HTTP Alternate (see Port 80)
+http-alt 591/udp #FileMaker, Inc. - HTTP Alternate (see Port 80)
+eudora-set 592/tcp
+eudora-set 592/udp
+http-rpc-epmap 593/tcp #HTTP RPC Ep Map
+http-rpc-epmap 593/udp #HTTP RPC Ep Map
+tpip 594/tcp
+tpip 594/udp
+cab-protocol 595/tcp
+cab-protocol 595/udp
+smsd 596/tcp
+smsd 596/udp
+ptcnameservice 597/tcp #PTC Name Service
+ptcnameservice 597/udp #PTC Name Service
+sco-websrvrmg3 598/tcp #SCO Web Server Manager 3
+sco-websrvrmg3 598/udp #SCO Web Server Manager 3
+acp 599/tcp #Aeolon Core Protocol
+acp 599/udp #Aeolon Core Protocol
+ipcserver 600/tcp #Sun IPC server
+ipcserver 600/udp #Sun IPC server
+nqs 607/tcp
+nqs 607/udp
+urm 606/tcp #Cray Unified Resource Manager
+urm 606/udp #Cray Unified Resource Manager
+sift-uft 608/tcp #Sender-Initiated/Unsolicited File Transfer
+sift-uft 608/udp #Sender-Initiated/Unsolicited File Transfer
+npmp-trap 609/tcp
+npmp-trap 609/udp
+npmp-local 610/tcp
+npmp-local 610/udp
+npmp-gui 611/tcp
+npmp-gui 611/udp
+sshell 614/tcp #SSLshell
+sshell 614/udp
+ipp 631/tcp #IPP (Internet Printing Protocol)
+ipp 631/udp #IPP (Internet Printing Protocol)
+ginad 634/tcp
+ginad 634/udp
+ldaps 636/tcp sldap #ldap protocol over TLS/SSL
+ldaps 636/udp sldap
+mdqs 666/tcp
+mdqs 666/udp
+#PROBLEMS!===============================================
+doom 666/tcp #doom Id Software
+doom 666/udp #doom Id Software
+#PROBLEMS!===============================================
+acap 674/tcp #Application Configuration Access Protocol
+acap 674/udp #Application Configuration Access Protocol
+elcsd 704/tcp #errlog copy/server daemon
+elcsd 704/udp #errlog copy/server daemon
+entrustmanager 709/tcp #EntrustManager
+entrustmanager 709/udp #EntrustManager
+netviewdm1 729/tcp #IBM NetView DM/6000 Server/Client
+netviewdm1 729/udp #IBM NetView DM/6000 Server/Client
+netviewdm2 730/tcp #IBM NetView DM/6000 send/tcp
+netviewdm2 730/udp #IBM NetView DM/6000 send/tcp
+netviewdm3 731/tcp #IBM NetView DM/6000 receive/tcp
+netviewdm3 731/udp #IBM NetView DM/6000 receive/tcp
+netgw 741/tcp
+netgw 741/udp
+netrcs 742/tcp #Network based Rev. Cont. Sys.
+netrcs 742/udp #Network based Rev. Cont. Sys.
+flexlm 744/tcp #Flexible License Manager
+flexlm 744/udp #Flexible License Manager
+fujitsu-dev 747/tcp #Fujitsu Device Control
+fujitsu-dev 747/udp #Fujitsu Device Control
+ris-cm 748/tcp #Russell Info Sci Calendar Manager
+ris-cm 748/udp #Russell Info Sci Calendar Manager
+kerberos-adm 749/tcp #Kerberos administration (v5)
+kerberos-adm 749/udp #Kerberos administration (v5)
+kerberos-iv 750/udp kdc # Kerberos (v4)
+kerberos-iv 750/tcp kdc # Kerberos (v4)
+#PROBLEMS!========================================================
+#rfile 750/tcp
+#loadav 750/udp
+#PROBLEMS!========================================================
+kerberos_master 751/tcp # Kerberos `kadmin' (v4)
+kerberos_master 751/udp # Kerberos `kadmin' (v4)
+#PROBLEMS!========================================================
+pump 751/tcp
+pump 751/udp
+#PROBLEMS!========================================================
+qrh 752/tcp
+qrh 752/udp
+rrh 753/tcp
+rrh 753/udp
+krb_prop 754/tcp krb5_prop # kerberos/v5 server propagation
+#PROBLEMS!========================================================
+tell 754/tcp #send
+#PROBLEMS!========================================================
+tell 754/udp #send
+nlogin 758/tcp
+nlogin 758/udp
+con 759/tcp
+con 759/udp
+krbupdate 760/tcp kreg # Kerberos (v4) registration
+#PROBLEMS!========================================================
+ns 760/tcp
+#PROBLEMS!========================================================
+ns 760/udp
+kpasswd 761/tcp kpwd # Kerberos (v4) "passwd"
+#PROBLEMS!========================================================
+rxe 761/tcp
+#PROBLEMS!========================================================
+rxe 761/udp
+quotad 762/tcp
+quotad 762/udp
+cycleserv 763/tcp
+cycleserv 763/udp
+omserv 764/tcp
+omserv 764/udp
+webster 765/tcp
+webster 765/udp
+phonebook 767/tcp #phone
+phonebook 767/udp #phone
+vid 769/tcp
+vid 769/udp
+cadlock 770/tcp
+cadlock 770/udp
+rtip 771/tcp
+rtip 771/udp
+cycleserv2 772/tcp
+cycleserv2 772/udp
+submit 773/tcp
+notify 773/udp
+rpasswd 774/tcp
+acmaint_dbd 774/udp
+entomb 775/tcp
+acmaint_transd 775/udp
+wpages 776/tcp
+wpages 776/udp
+wpgs 780/tcp
+wpgs 780/udp
+concert 786/tcp
+concert 786/udp
+mdbs_daemon 800/tcp
+mdbs_daemon 800/udp
+device 801/tcp
+device 801/udp
+supfilesrv 871/tcp # for SUP
+rsync 873/tcp
+rsync 873/udp
+accessbuilder 888/tcp
+accessbuilder 888/udp
+swat 901/tcp # samba web configuration tool
+ftps-data 989/tcp # ftp protocol, data, over TLS/SSL
+ftps-data 989/udp
+ftps 990/tcp # ftp protocol, control, over TLS/SSL
+ftps 990/udp
+telnets 992/tcp # telnet protocol over TLS/SSL
+telnets 992/udp
+imaps 993/tcp # imap4 protocol over TLS/SSL
+imaps 993/udp
+ircs 994/tcp # irc protocol over TLS/SSL
+ircs 994/udp
+pop3s 995/tcp spop3 # pop3 protocol over TLS/SSL
+pop3s 995/udp spop3
+vsinet 996/tcp
+vsinet 996/udp
+maitrd 997/tcp
+maitrd 997/udp
+busboy 998/tcp
+puparp 998/udp
+garcon 999/tcp
+applix 999/udp #Applix ac
+puprouter 999/tcp
+puprouter 999/udp
+cadlock 1000/tcp
+ock 1000/udp
+#
+# REGISTERED PORT NUMBERS
+#
+blackjack 1025/tcp #network blackjack
+blackjack 1025/udp #network blackjack
+iad1 1030/tcp #BBN IAD
+iad1 1030/udp #BBN IAD
+iad2 1031/tcp #BBN IAD
+iad2 1031/udp #BBN IAD
+iad3 1032/tcp #BBN IAD
+iad3 1032/udp #BBN IAD
+nim 1058/tcp
+nim 1058/udp
+nimreg 1059/tcp
+nimreg 1059/udp
+instl_boots 1067/tcp #Installation Bootstrap Proto. Serv.
+instl_boots 1067/udp #Installation Bootstrap Proto. Serv.
+instl_bootc 1068/tcp #Installation Bootstrap Proto. Cli.
+instl_bootc 1068/udp #Installation Bootstrap Proto. Cli.
+socks 1080/tcp
+socks 1080/udp
+ansoft-lm-1 1083/tcp #Anasoft License Manager
+ansoft-lm-1 1083/udp #Anasoft License Manager
+ansoft-lm-2 1084/tcp #Anasoft License Manager
+ansoft-lm-2 1084/udp #Anasoft License Manager
+webobjects 1085/tcp #Web Objects
+webobjects 1085/udp #Web Objects
+kpop 1109/tcp #Unofficial
+kpop 1109/udp #Unofficial
+nfsd-status 1110/tcp #Cluster status info
+nfsd-keepalive 1110/udp #Client status info
+supfiledbg 1127/tcp # for SUP
+nfa 1155/tcp #Network File Access
+nfa 1155/udp #Network File Access
+phone 1167/udp #conference calling
+skkserv 1178/tcp #SKK (kanji input)
+lupa 1212/tcp
+lupa 1212/udp
+nerv 1222/tcp #SNI R&D network
+nerv 1222/udp #SNI R&D network
+hermes 1248/tcp
+hermes 1248/udp
+healthd 1281/tcp #healthd
+healthd 1281/udp #healthd
+alta-ana-lm 1346/tcp #Alta Analytics License Manager
+alta-ana-lm 1346/udp #Alta Analytics License Manager
+bbn-mmc 1347/tcp #multi media conferencing
+bbn-mmc 1347/udp #multi media conferencing
+bbn-mmx 1348/tcp #multi media conferencing
+bbn-mmx 1348/udp #multi media conferencing
+sbook 1349/tcp #Registration Network Protocol
+sbook 1349/udp #Registration Network Protocol
+editbench 1350/tcp #Registration Network Protocol
+editbench 1350/udp #Registration Network Protocol
+equationbuilder 1351/tcp #Digital Tool Works (MIT)
+equationbuilder 1351/udp #Digital Tool Works (MIT)
+lotusnote 1352/tcp #Lotus Note
+lotusnote 1352/udp #Lotus Note
+relief 1353/tcp #Relief Consulting
+relief 1353/udp #Relief Consulting
+rightbrain 1354/tcp #RightBrain Software
+rightbrain 1354/udp #RightBrain Software
+intuitive-edge 1355/tcp #Intuitive Edge
+intuitive-edge 1355/udp #Intuitive Edge
+cuillamartin 1356/tcp #CuillaMartin Company
+cuillamartin 1356/udp #CuillaMartin Company
+pegboard 1357/tcp #Electronic PegBoard
+pegboard 1357/udp #Electronic PegBoard
+connlcli 1358/tcp
+connlcli 1358/udp
+ftsrv 1359/tcp
+ftsrv 1359/udp
+mimer 1360/tcp
+mimer 1360/udp
+linx 1361/tcp
+linx 1361/udp
+timeflies 1362/tcp
+timeflies 1362/udp
+ndm-requester 1363/tcp #Network DataMover Requester
+ndm-requester 1363/udp #Network DataMover Requester
+ndm-server 1364/tcp #Network DataMover Server
+ndm-server 1364/udp #Network DataMover Server
+adapt-sna 1365/tcp #Network Software Associates
+adapt-sna 1365/udp #Network Software Associates
+netware-csp 1366/tcp #Novell NetWare Comm Service Platform
+netware-csp 1366/udp #Novell NetWare Comm Service Platform
+dcs 1367/tcp
+dcs 1367/udp
+screencast 1368/tcp
+screencast 1368/udp
+gv-us 1369/tcp #GlobalView to Unix Shell
+gv-us 1369/udp #GlobalView to Unix Shell
+us-gv 1370/tcp #Unix Shell to GlobalView
+us-gv 1370/udp #Unix Shell to GlobalView
+fc-cli 1371/tcp #Fujitsu Config Protocol
+fc-cli 1371/udp #Fujitsu Config Protocol
+fc-ser 1372/tcp #Fujitsu Config Protocol
+fc-ser 1372/udp #Fujitsu Config Protocol
+chromagrafx 1373/tcp
+chromagrafx 1373/udp
+molly 1374/tcp #EPI Software Systems
+molly 1374/udp #EPI Software Systems
+bytex 1375/tcp
+bytex 1375/udp
+ibm-pps 1376/tcp #IBM Person to Person Software
+ibm-pps 1376/udp #IBM Person to Person Software
+cichlid 1377/tcp #Cichlid License Manager
+cichlid 1377/udp #Cichlid License Manager
+elan 1378/tcp #Elan License Manager
+elan 1378/udp #Elan License Manager
+dbreporter 1379/tcp #Integrity Solutions
+dbreporter 1379/udp #Integrity Solutions
+telesis-licman 1380/tcp #Telesis Network License Manager
+telesis-licman 1380/udp #Telesis Network License Manager
+apple-licman 1381/tcp #Apple Network License Manager
+apple-licman 1381/udp #Apple Network License Manager
+#udt_os 1382/tcp
+#udt_os 1382/udp
+gwha 1383/tcp #GW Hannaway Network License Manager
+gwha 1383/udp #GW Hannaway Network License Manager
+os-licman 1384/tcp #Objective Solutions License Manager
+os-licman 1384/udp #Objective Solutions License Manager
+atex_elmd 1385/tcp #Atex Publishing License Manager
+atex_elmd 1385/udp #Atex Publishing License Manager
+checksum 1386/tcp #CheckSum License Manager
+checksum 1386/udp #CheckSum License Manager
+cadsi-lm 1387/tcp #Computer Aided Design Software Inc LM
+cadsi-lm 1387/udp #Computer Aided Design Software Inc LM
+objective-dbc 1388/tcp #Objective Solutions DataBase Cache
+objective-dbc 1388/udp #Objective Solutions DataBase Cache
+iclpv-dm 1389/tcp #Document Manager
+iclpv-dm 1389/udp #Document Manager
+iclpv-sc 1390/tcp #Storage Controller
+iclpv-sc 1390/udp #Storage Controller
+iclpv-sas 1391/tcp #Storage Access Server
+iclpv-sas 1391/udp #Storage Access Server
+iclpv-pm 1392/tcp #Print Manager
+iclpv-pm 1392/udp #Print Manager
+iclpv-nls 1393/tcp #Network Log Server
+iclpv-nls 1393/udp #Network Log Server
+iclpv-nlc 1394/tcp #Network Log Client
+iclpv-nlc 1394/udp #Network Log Client
+iclpv-wsm 1395/tcp #PC Workstation Manager software
+iclpv-wsm 1395/udp #PC Workstation Manager software
+dvl-activemail 1396/tcp #DVL Active Mail
+dvl-activemail 1396/udp #DVL Active Mail
+audio-activmail 1397/tcp #Audio Active Mail
+audio-activmail 1397/udp #Audio Active Mail
+video-activmail 1398/tcp #Video Active Mail
+video-activmail 1398/udp #Video Active Mail
+cadkey-licman 1399/tcp #Cadkey License Manager
+cadkey-licman 1399/udp #Cadkey License Manager
+cadkey-tablet 1400/tcp #Cadkey Tablet Daemon
+cadkey-tablet 1400/udp #Cadkey Tablet Daemon
+goldleaf-licman 1401/tcp #Goldleaf License Manager
+goldleaf-licman 1401/udp #Goldleaf License Manager
+prm-sm-np 1402/tcp #Prospero Resource Manager
+prm-sm-np 1402/udp #Prospero Resource Manager
+prm-nm-np 1403/tcp #Prospero Resource Manager
+prm-nm-np 1403/udp #Prospero Resource Manager
+igi-lm 1404/tcp #Infinite Graphics License Manager
+igi-lm 1404/udp #Infinite Graphics License Manager
+ibm-res 1405/tcp #IBM Remote Execution Starter
+ibm-res 1405/udp #IBM Remote Execution Starter
+netlabs-lm 1406/tcp #NetLabs License Manager
+netlabs-lm 1406/udp #NetLabs License Manager
+dbsa-lm 1407/tcp #DBSA License Manager
+dbsa-lm 1407/udp #DBSA License Manager
+sophia-lm 1408/tcp #Sophia License Manager
+sophia-lm 1408/udp #Sophia License Manager
+here-lm 1409/tcp #Here License Manager
+here-lm 1409/udp #Here License Manager
+hiq 1410/tcp #HiQ License Manager
+hiq 1410/udp #HiQ License Manager
+af 1411/tcp #AudioFile
+af 1411/udp #AudioFile
+innosys 1412/tcp
+innosys 1412/udp
+innosys-acl 1413/tcp
+innosys-acl 1413/udp
+ibm-mqseries 1414/tcp #IBM MQSeries
+ibm-mqseries 1414/udp #IBM MQSeries
+dbstar 1415/tcp
+dbstar 1415/udp
+novell-lu6.2 1416/tcp #Novell LU6.2
+novell-lu6.2 1416/udp #Novell LU6.2
+timbuktu-srv1 1417/tcp #Timbuktu Service 1 Port
+timbuktu-srv1 1417/udp #Timbuktu Service 1 Port
+timbuktu-srv2 1418/tcp #Timbuktu Service 2 Port
+timbuktu-srv2 1418/udp #Timbuktu Service 2 Port
+timbuktu-srv3 1419/tcp #Timbuktu Service 3 Port
+timbuktu-srv3 1419/udp #Timbuktu Service 3 Port
+timbuktu-srv4 1420/tcp #Timbuktu Service 4 Port
+timbuktu-srv4 1420/udp #Timbuktu Service 4 Port
+gandalf-lm 1421/tcp #Gandalf License Manager
+gandalf-lm 1421/udp #Gandalf License Manager
+autodesk-lm 1422/tcp #Autodesk License Manager
+autodesk-lm 1422/udp #Autodesk License Manager
+essbase 1423/tcp #Essbase Arbor Software
+essbase 1423/udp #Essbase Arbor Software
+hybrid 1424/tcp #Hybrid Encryption Protocol
+hybrid 1424/udp #Hybrid Encryption Protocol
+zion-lm 1425/tcp #Zion Software License Manager
+zion-lm 1425/udp #Zion Software License Manager
+sas-1 1426/tcp #Satellite-data Acquisition System 1
+sas-1 1426/udp #Satellite-data Acquisition System 1
+mloadd 1427/tcp #mloadd monitoring tool
+mloadd 1427/udp #mloadd monitoring tool
+informatik-lm 1428/tcp #Informatik License Manager
+informatik-lm 1428/udp #Informatik License Manager
+nms 1429/tcp #Hypercom NMS
+nms 1429/udp #Hypercom NMS
+tpdu 1430/tcp #Hypercom TPDU
+tpdu 1430/udp #Hypercom TPDU
+rgtp 1431/tcp #Reverse Gossip Transport
+rgtp 1431/udp #Reverse Gossip Transport
+blueberry-lm 1432/tcp #Blueberry Software License Manager
+blueberry-lm 1432/udp #Blueberry Software License Manager
+ms-sql-s 1433/tcp #Microsoft-SQL-Server
+ms-sql-s 1433/udp #Microsoft-SQL-Server
+ms-sql-m 1434/tcp #Microsoft-SQL-Monitor
+ms-sql-m 1434/udp #Microsoft-SQL-Monitor
+ibm-cics 1435/tcp
+ibm-cics 1435/udp
+sas-2 1436/tcp #Satellite-data Acquisition System 2
+sas-2 1436/udp #Satellite-data Acquisition System 2
+tabula 1437/tcp
+tabula 1437/udp
+eicon-server 1438/tcp #Eicon Security Agent/Server
+eicon-server 1438/udp #Eicon Security Agent/Server
+eicon-x25 1439/tcp #Eicon X25/SNA Gateway
+eicon-x25 1439/udp #Eicon X25/SNA Gateway
+eicon-slp 1440/tcp #Eicon Service Location Protocol
+eicon-slp 1440/udp #Eicon Service Location Protocol
+cadis-1 1441/tcp #Cadis License Management
+cadis-1 1441/udp #Cadis License Management
+cadis-2 1442/tcp #Cadis License Management
+cadis-2 1442/udp #Cadis License Management
+ies-lm 1443/tcp #Integrated Engineering Software
+ies-lm 1443/udp #Integrated Engineering Software
+marcam-lm 1444/tcp #Marcam License Management
+marcam-lm 1444/udp #Marcam License Management
+proxima-lm 1445/tcp #Proxima License Manager
+proxima-lm 1445/udp #Proxima License Manager
+ora-lm 1446/tcp #Optical Research Associates License Manager
+ora-lm 1446/udp #Optical Research Associates License Manager
+apri-lm 1447/tcp #Applied Parallel Research LM
+apri-lm 1447/udp #Applied Parallel Research LM
+oc-lm 1448/tcp #OpenConnect License Manager
+oc-lm 1448/udp #OpenConnect License Manager
+peport 1449/tcp
+peport 1449/udp
+dwf 1450/tcp #Tandem Distributed Workbench Facility
+dwf 1450/udp #Tandem Distributed Workbench Facility
+infoman 1451/tcp #IBM Information Management
+infoman 1451/udp #IBM Information Management
+gtegsc-lm 1452/tcp #GTE Government Systems License Man
+gtegsc-lm 1452/udp #GTE Government Systems License Man
+genie-lm 1453/tcp #Genie License Manager
+genie-lm 1453/udp #Genie License Manager
+interhdl_elmd 1454/tcp #interHDL License Manager
+interhdl_elmd 1454/udp #interHDL License Manager
+esl-lm 1455/tcp #ESL License Manager
+esl-lm 1455/udp #ESL License Manager
+dca 1456/tcp
+dca 1456/udp
+valisys-lm 1457/tcp #Valisys License Manager
+valisys-lm 1457/udp #Valisys License Manager
+nrcabq-lm 1458/tcp #Nichols Research Corp.
+nrcabq-lm 1458/udp #Nichols Research Corp.
+proshare1 1459/tcp #Proshare Notebook Application
+proshare1 1459/udp #Proshare Notebook Application
+proshare2 1460/tcp #Proshare Notebook Application
+proshare2 1460/udp #Proshare Notebook Application
+ibm_wrless_lan 1461/tcp #IBM Wireless LAN
+ibm_wrless_lan 1461/udp #IBM Wireless LAN
+world-lm 1462/tcp #World License Manager
+world-lm 1462/udp #World License Manager
+nucleus 1463/tcp
+nucleus 1463/udp
+msl_lmd 1464/tcp #MSL License Manager
+msl_lmd 1464/udp #MSL License Manager
+pipes 1465/tcp #Pipes Platform
+pipes 1465/udp #Pipes Platform mfarlin@peerlogic.com
+oceansoft-lm 1466/tcp #Ocean Software License Manager
+oceansoft-lm 1466/udp #Ocean Software License Manager
+csdmbase 1467/tcp
+csdmbase 1467/udp
+csdm 1468/tcp
+csdm 1468/udp
+aal-lm 1469/tcp #Active Analysis Limited License Manager
+aal-lm 1469/udp #Active Analysis Limited License Manager
+uaiact 1470/tcp #Universal Analytics
+uaiact 1470/udp #Universal Analytics
+csdmbase 1471/tcp
+csdmbase 1471/udp
+csdm 1472/tcp
+csdm 1472/udp
+openmath 1473/tcp
+openmath 1473/udp
+telefinder 1474/tcp
+telefinder 1474/udp
+taligent-lm 1475/tcp #Taligent License Manager
+taligent-lm 1475/udp #Taligent License Manager
+clvm-cfg 1476/tcp
+clvm-cfg 1476/udp
+ms-sna-server 1477/tcp
+ms-sna-server 1477/udp
+ms-sna-base 1478/tcp
+ms-sna-base 1478/udp
+dberegister 1479/tcp
+dberegister 1479/udp
+pacerforum 1480/tcp
+pacerforum 1480/udp
+airs 1481/tcp
+airs 1481/udp
+miteksys-lm 1482/tcp #Miteksys License Manager
+miteksys-lm 1482/udp #Miteksys License Manager
+afs 1483/tcp #AFS License Manager
+afs 1483/udp #AFS License Manager
+confluent 1484/tcp #Confluent License Manager
+confluent 1484/udp #Confluent License Manager
+lansource 1485/tcp
+lansource 1485/udp
+nms_topo_serv 1486/tcp
+nms_topo_serv 1486/udp
+localinfosrvr 1487/tcp
+localinfosrvr 1487/udp
+docstor 1488/tcp
+docstor 1488/udp
+dmdocbroker 1489/tcp
+dmdocbroker 1489/udp
+insitu-conf 1490/tcp
+insitu-conf 1490/udp
+anynetgateway 1491/tcp
+anynetgateway 1491/udp
+stone-design-1 1492/tcp
+stone-design-1 1492/udp
+netmap_lm 1493/tcp
+netmap_lm 1493/udp
+ica 1494/tcp
+ica 1494/udp
+cvc 1495/tcp
+cvc 1495/udp
+liberty-lm 1496/tcp
+liberty-lm 1496/udp
+rfx-lm 1497/tcp
+rfx-lm 1497/udp
+watcom-sql 1498/tcp
+watcom-sql 1498/udp
+fhc 1499/tcp #Federico Heinz Consultora
+fhc 1499/udp #Federico Heinz Consultora
+vlsi-lm 1500/tcp #VLSI License Manager
+vlsi-lm 1500/udp #VLSI License Manager
+sas-3 1501/tcp #Satellite-data Acquisition System 3
+sas-3 1501/udp #Satellite-data Acquisition System 3
+shivadiscovery 1502/tcp #Shiva
+shivadiscovery 1502/udp #Shiva
+imtc-mcs 1503/tcp #Databeam
+imtc-mcs 1503/udp #Databeam
+evb-elm 1504/tcp #EVB Software Engineering License Manager
+evb-elm 1504/udp #EVB Software Engineering License Manager
+funkproxy 1505/tcp #Funk Software, Inc.
+funkproxy 1505/udp #Funk Software, Inc.
+utcd 1506/tcp #Universal Time daemon (utcd)
+utcd 1506/udp #Universal Time daemon (utcd)
+symplex 1507/tcp
+symplex 1507/udp
+diagmond 1508/tcp
+diagmond 1508/udp
+robcad-lm 1509/tcp #Robcad, Ltd. License Manager
+robcad-lm 1509/udp #Robcad, Ltd. License Manager
+mvx-lm 1510/tcp #Midland Valley Exploration Ltd. Lic. Man.
+mvx-lm 1510/udp #Midland Valley Exploration Ltd. Lic. Man.
+3l-l1 1511/tcp
+3l-l1 1511/udp
+wins 1512/tcp #Microsoft's Windows Internet Name Service
+wins 1512/udp #Microsoft's Windows Internet Name Service
+fujitsu-dtc 1513/tcp #Fujitsu Systems Business of America, Inc
+fujitsu-dtc 1513/udp #Fujitsu Systems Business of America, Inc
+fujitsu-dtcns 1514/tcp #Fujitsu Systems Business of America, Inc
+fujitsu-dtcns 1514/udp #Fujitsu Systems Business of America, Inc
+ifor-protocol 1515/tcp
+ifor-protocol 1515/udp
+vpad 1516/tcp #Virtual Places Audio data
+vpad 1516/udp #Virtual Places Audio data
+vpac 1517/tcp #Virtual Places Audio control
+vpac 1517/udp #Virtual Places Audio control
+vpvd 1518/tcp #Virtual Places Video data
+vpvd 1518/udp #Virtual Places Video data
+vpvc 1519/tcp #Virtual Places Video control
+vpvc 1519/udp #Virtual Places Video control
+atm-zip-office 1520/tcp #atm zip office
+atm-zip-office 1520/udp #atm zip office
+ncube-lm 1521/tcp #nCube License Manager
+ncube-lm 1521/udp #nCube License Manager
+rna-lm 1522/tcp #Ricardo North America License Manager
+rna-lm 1522/udp #Ricardo North America License Manager
+cichild-lm 1523/tcp
+cichild-lm 1523/udp
+ingreslock 1524/tcp #ingres
+ingreslock 1524/udp #ingres
+prospero-np 1525/tcp #Prospero Directory Service non-priv
+prospero-np 1525/udp #Prospero Directory Service non-priv
+#PROBLEMS!========================================================
+orasrv 1525/tcp #oracle
+orasrv 1525/udp #oracle
+#PROBLEMS!========================================================
+pdap-np 1526/tcp #Prospero Data Access Prot non-priv
+pdap-np 1526/udp #Prospero Data Access Prot non-priv
+tlisrv 1527/tcp #oracle
+tlisrv 1527/udp #oracle
+mciautoreg 1528/tcp
+mciautoreg 1528/udp
+support 1529/tcp prmsd gnatsd # cygnus bug tracker
+coauthor 1529/tcp #oracle
+coauthor 1529/udp #oracle
+rap-service 1530/tcp
+rap-service 1530/udp
+rap-listen 1531/tcp
+rap-listen 1531/udp
+miroconnect 1532/tcp
+miroconnect 1532/udp
+virtual-places 1533/tcp #Virtual Places Software
+virtual-places 1533/udp #Virtual Places Software
+micromuse-lm 1534/tcp
+micromuse-lm 1534/udp
+ampr-info 1535/tcp
+ampr-info 1535/udp
+ampr-inter 1536/tcp
+ampr-inter 1536/udp
+sdsc-lm 1537/tcp
+sdsc-lm 1537/udp
+3ds-lm 1538/tcp
+3ds-lm 1538/udp
+intellistor-lm 1539/tcp #Intellistor License Manager
+intellistor-lm 1539/udp #Intellistor License Manager
+rds 1540/tcp
+rds 1540/udp
+rds2 1541/tcp
+rds2 1541/udp
+gridgen-elmd 1542/tcp
+gridgen-elmd 1542/udp
+simba-cs 1543/tcp
+simba-cs 1543/udp
+aspeclmd 1544/tcp
+aspeclmd 1544/udp
+vistium-share 1545/tcp
+vistium-share 1545/udp
+abbaccuray 1546/tcp
+abbaccuray 1546/udp
+laplink 1547/tcp
+laplink 1547/udp
+axon-lm 1548/tcp #Axon License Manager
+axon-lm 1548/udp #Axon License Manager
+shivahose 1549/tcp #Shiva Hose
+shivasound 1549/udp #Shiva Sound
+3m-image-lm 1550/tcp #Image Storage license manager 3M Company
+3m-image-lm 1550/udp #Image Storage license manager 3M Company
+hecmtl-db 1551/tcp
+hecmtl-db 1551/udp
+pciarray 1552/tcp
+pciarray 1552/udp
+issd 1600/tcp
+issd 1600/udp
+# IMPORTANT NOTE: Ports 1645/1646 are the traditional radius ports used by
+# many vendors without obtaining official IANA assignment. The official
+# assignment is now ports 1812/1813 and users are encouraged to migrate
+# when possible to these new ports.
+#radius 1645/udp #RADIUS authentication protocol (old)
+#radacct 1646/udp #RADIUS accounting protocol (old)
+nkd 1650/tcp
+nkd 1650/udp
+shiva_confsrvr 1651/tcp
+shiva_confsrvr 1651/udp
+xnmp 1652/tcp
+xnmp 1652/udp
+netview-aix-1 1661/tcp
+netview-aix-1 1661/udp
+netview-aix-2 1662/tcp
+netview-aix-2 1662/udp
+netview-aix-3 1663/tcp
+netview-aix-3 1663/udp
+netview-aix-4 1664/tcp
+netview-aix-4 1664/udp
+netview-aix-5 1665/tcp
+netview-aix-5 1665/udp
+netview-aix-6 1666/tcp
+netview-aix-6 1666/udp
+netview-aix-7 1667/tcp
+netview-aix-7 1667/udp
+netview-aix-8 1668/tcp
+netview-aix-8 1668/udp
+netview-aix-9 1669/tcp
+netview-aix-9 1669/udp
+netview-aix-10 1670/tcp
+netview-aix-10 1670/udp
+netview-aix-11 1671/tcp
+netview-aix-11 1671/udp
+netview-aix-12 1672/tcp
+netview-aix-12 1672/udp
+l2f 1701/tcp #l2f
+l2f 1701/udp #l2f
+l2tp 1701/tcp #Layer 2 Tunnelling Protocol
+l2tp 1701/udp #Layer 2 Tunnelling Protocol
+pptp 1723/tcp #Point-to-point tunnelling protocol
+# IMPORTANT NOTE: See comments for ports 1645/1646 when using older equipment
+radius 1812/udp #RADIUS authentication protocol (IANA sanctioned)
+radacct 1813/udp #RADIUS accounting protocol (IANA sanctioned)
+licensedaemon 1986/tcp #cisco license management
+licensedaemon 1986/udp #cisco license management
+tr-rsrb-p1 1987/tcp #cisco RSRB Priority 1 port
+tr-rsrb-p1 1987/udp #cisco RSRB Priority 1 port
+tr-rsrb-p2 1988/tcp #cisco RSRB Priority 2 port
+tr-rsrb-p2 1988/udp #cisco RSRB Priority 2 port
+tr-rsrb-p3 1989/tcp #cisco RSRB Priority 3 port
+tr-rsrb-p3 1989/udp #cisco RSRB Priority 3 port
+#PROBLEMS!===================================================
+mshnet 1989/tcp #MHSnet system
+mshnet 1989/udp #MHSnet system
+#PROBLEMS!===================================================
+stun-p1 1990/tcp #cisco STUN Priority 1 port
+stun-p1 1990/udp #cisco STUN Priority 1 port
+stun-p2 1991/tcp #cisco STUN Priority 2 port
+stun-p2 1991/udp #cisco STUN Priority 2 port
+stun-p3 1992/tcp #cisco STUN Priority 3 port
+stun-p3 1992/udp #cisco STUN Priority 3 port
+#PROBLEMS!===================================================
+ipsendmsg 1992/tcp
+ipsendmsg 1992/udp
+#PROBLEMS!===================================================
+snmp-tcp-port 1993/tcp #cisco SNMP TCP port
+snmp-tcp-port 1993/udp #cisco SNMP TCP port
+stun-port 1994/tcp #cisco serial tunnel port
+stun-port 1994/udp #cisco serial tunnel port
+perf-port 1995/tcp #cisco perf port
+perf-port 1995/udp #cisco perf port
+tr-rsrb-port 1996/tcp #cisco Remote SRB port
+tr-rsrb-port 1996/udp #cisco Remote SRB port
+gdp-port 1997/tcp #cisco Gateway Discovery Protocol
+gdp-port 1997/udp #cisco Gateway Discovery Protocol
+x25-svc-port 1998/tcp #cisco X.25 service (XOT)
+x25-svc-port 1998/udp #cisco X.25 service (XOT)
+tcp-id-port 1999/tcp #cisco identification port
+tcp-id-port 1999/udp #cisco identification port
+callbook 2000/tcp
+callbook 2000/udp
+dc 2001/tcp
+wizard 2001/udp #curry
+globe 2002/tcp
+globe 2002/udp
+cfingerd 2003/tcp #GNU finger
+mailbox 2004/tcp
+emce 2004/udp #CCWS mm conf
+berknet 2005/tcp
+oracle 2005/udp
+invokator 2006/tcp
+raid-cc 2006/udp #raid
+dectalk 2007/tcp
+raid-am 2007/udp
+conf 2008/tcp
+terminaldb 2008/udp
+news 2009/tcp
+whosockami 2009/udp
+search 2010/tcp
+pipe_server 2010/udp
+raid-cc 2011/tcp #raid
+servserv 2011/udp
+ttyinfo 2012/tcp
+raid-ac 2012/udp
+raid-am 2013/tcp
+raid-cd 2013/udp
+troff 2014/tcp
+raid-sf 2014/udp
+cypress 2015/tcp
+raid-cs 2015/udp
+bootserver 2016/tcp
+bootserver 2016/udp
+cypress-stat 2017/tcp
+bootclient 2017/udp
+terminaldb 2018/tcp
+rellpack 2018/udp
+whosockami 2019/tcp
+about 2019/udp
+xinupageserver 2020/tcp
+xinupageserver 2020/udp
+servexec 2021/tcp
+xinuexpansion1 2021/udp
+down 2022/tcp
+xinuexpansion2 2022/udp
+xinuexpansion3 2023/tcp
+xinuexpansion3 2023/udp
+xinuexpansion4 2024/tcp
+xinuexpansion4 2024/udp
+ellpack 2025/tcp
+xribs 2025/udp
+scrabble 2026/tcp
+scrabble 2026/udp
+shadowserver 2027/tcp
+shadowserver 2027/udp
+submitserver 2028/tcp
+submitserver 2028/udp
+device2 2030/tcp
+device2 2030/udp
+blackboard 2032/tcp
+blackboard 2032/udp
+glogger 2033/tcp
+glogger 2033/udp
+scoremgr 2034/tcp
+scoremgr 2034/udp
+imsldoc 2035/tcp
+imsldoc 2035/udp
+objectmanager 2038/tcp
+objectmanager 2038/udp
+lam 2040/tcp
+lam 2040/udp
+interbase 2041/tcp
+interbase 2041/udp
+isis 2042/tcp
+isis 2042/udp
+isis-bcast 2043/tcp
+isis-bcast 2043/udp
+rimsl 2044/tcp
+rimsl 2044/udp
+cdfunc 2045/tcp
+cdfunc 2045/udp
+sdfunc 2046/tcp
+sdfunc 2046/udp
+#dls 2047/tcp
+#dls 2047/udp
+dls-monitor 2048/tcp
+dls-monitor 2048/udp
+nfsd 2049/tcp nfs # NFS server daemon
+nfsd 2049/udp nfs # NFS server daemon
+#PROBLEMS!=============================================================
+#shilp 2049/tcp
+#shilp 2049/udp
+#PROBLEMS!=============================================================
+dlsrpn 2065/tcp #Data Link Switch Read Port Number
+dlsrpn 2065/udp #Data Link Switch Read Port Number
+dlswpn 2067/tcp #Data Link Switch Write Port Number
+dlswpn 2067/udp #Data Link Switch Write Port Number
+zephyr-clt 2103/udp #Zephyr serv-hm connection
+zephyr-hm 2104/udp #Zephyr hostmanager
+#PROBLEMS!=============================================================
+#zephyr-hm-srv 2105/udp #Zephyr hm-serv connection
+#PROBLEMS!=============================================================
+eklogin 2105/tcp #Kerberos (v4) encrypted rlogin
+eklogin 2105/udp #Kerberos (v4) encrypted rlogin
+ekshell 2106/tcp #Kerberos (v4) encrypted rshell
+ekshell 2106/udp #Kerberos (v4) encrypted rshell
+rkinit 2108/tcp #Kerberos (v4) remote initialization
+rkinit 2108/udp #Kerberos (v4) remote initialization
+ats 2201/tcp #Advanced Training System Program
+ats 2201/udp #Advanced Training System Program
+ivs-video 2232/tcp #IVS Video default
+ivs-video 2232/udp #IVS Video default
+ivsd 2241/tcp #IVS Daemon
+ivsd 2241/udp #IVS Daemon
+pehelp 2307/tcp
+pehelp 2307/udp
+cvspserver 2401/tcp #CVS network server
+cvspserver 2401/udp #CVS network server
+venus 2430/tcp #venus
+venus 2430/udp #venus
+venus-se 2431/tcp #venus-se
+venus-se 2431/udp #venus-se
+codasrv 2432/tcp #codasrv
+codasrv 2432/udp #codasrv
+codasrv-se 2433/tcp #codasrv-se
+codasrv-se 2433/udp #codasrv-se
+rtsserv 2500/tcp #Resource Tracking system server
+rtsserv 2500/udp #Resource Tracking system server
+rtsclient 2501/tcp #Resource Tracking system client
+rtsclient 2501/udp #Resource Tracking system client
+hp-3000-telnet 2564/tcp #HP 3000 NS/VT block mode telnet
+zebrasrv 2600/tcp #zebra service
+zebra 2601/tcp #zebra vty
+ripd 2602/tcp #RIPd vty
+ripngd 2603/tcp #RIPngd vty
+ospfd 2604/tcp #OSPFd vty
+bgpd 2605/tcp #BGPd vty
+ospf6d 2606/tcp #OSPF6d vty
+listen 2766/tcp #System V listener port
+www-dev 2784/tcp #world wide web - development
+www-dev 2784/udp #world wide web - development
+dict 2628/tcp #RFC 2229
+dict 2628/udp #RFC 2229
+eppc 3031/tcp #Remote AppleEvents/PPC Toolbox
+eppc 3031/udp #Remote AppleEvents/PPC Toolbox
+NSWS 3049/tcp
+NSWS 3049/udp
+sj3 3086/tcp #SJ3 (kanji input)
+vmodem 3141/tcp
+vmodem 3141/udp
+ccmail 3264/tcp #cc:mail/lotus
+ccmail 3264/udp #cc:mail/lotus
+dec-notes 3333/tcp #DEC Notes
+dec-notes 3333/udp #DEC Notes
+rsvp-encap 3455/udp #RSVP encapsulated in UDP
+mapper-nodemgr 3984/tcp #MAPPER network node manager
+mapper-nodemgr 3984/udp #MAPPER network node manager
+mapper-mapethd 3985/tcp #MAPPER TCP/IP server
+mapper-mapethd 3985/udp #MAPPER TCP/IP server
+mapper-ws_ethd 3986/tcp #MAPPER workstation server
+mapper-ws_ethd 3986/udp #MAPPER workstation server
+bmap 3421/tcp #Bull Apprise portmapper
+bmap 3421/udp #Bull Apprise portmapper
+prsvp 3455/tcp #RSVP Port
+prsvp 3455/udp #RSVP Port
+vat 3456/tcp #VAT default data
+vat 3456/udp #VAT default data
+vat-control 3457/tcp #VAT default control
+vat-control 3457/udp #VAT default control
+udt_os 3900/tcp #Unidata UDT OS
+udt_os 3900/udp #Unidata UDT OS
+netcheque 4008/tcp #NetCheque accounting
+netcheque 4008/udp #NetCheque accounting
+lockd 4045/udp # NFS lock daemon/manager
+lockd 4045/tcp
+nuts_dem 4132/tcp #NUTS Daemon
+nuts_dem 4132/udp #NUTS Daemon
+nuts_bootp 4133/tcp #NUTS Bootp Server
+nuts_bootp 4133/udp #NUTS Bootp Server
+rwhois 4321/tcp #Remote Who Is
+rwhois 4321/udp #Remote Who Is
+unicall 4343/tcp
+unicall 4343/udp
+krb524 4444/tcp
+krb524 4444/udp
+# PROBLEM krb524 assigned the port,
+# PROBLEM nv used it without an assignment
+nv-video 4444/tcp #NV Video default
+nv-video 4444/udp #NV Video default
+sae-urn 4500/tcp
+sae-urn 4500/udp
+fax 4557/tcp #FAX transmission service
+hylafax 4559/tcp #HylaFAX client-server protocol
+rfa 4672/tcp #remote file access server
+rfa 4672/udp #remote file access server
+commplex-main 5000/tcp
+commplex-main 5000/udp
+commplex-link 5001/tcp
+commplex-link 5001/udp
+rfe 5002/tcp #radio free ethernet
+rfe 5002/udp #radio free ethernet
+telelpathstart 5010/tcp
+telelpathstart 5010/udp
+telelpathattack 5011/tcp
+telelpathattack 5011/udp
+mmcc 5050/tcp #multimedia conference control tool
+mmcc 5050/udp #multimedia conference control tool
+rmonitor_secure 5145/tcp
+rmonitor_secure 5145/udp
+aol 5190/tcp #America-Online
+aol 5190/udp #America-Online
+aol-1 5191/tcp #AmericaOnline1
+aol-1 5191/udp #AmericaOnline1
+aol-2 5192/tcp #AmericaOnline2
+aol-2 5192/udp #AmericaOnline2
+aol-3 5193/tcp #AmericaOnline3
+aol-3 5193/udp #AmericaOnline3
+jabber-client 5222/tcp #Jabber Client Connection
+jabber-client 5222/udp #Jabber Client Connection
+padl2sim 5236/tcp
+padl2sim 5236/udp
+jabber-server 5269/tcp #Jabber Server Connection
+jabber-server 5269/udp #Jabber Server Connection
+hacl-hb 5300/tcp # HA cluster heartbeat
+hacl-hb 5300/udp # HA cluster heartbeat
+hacl-gs 5301/tcp # HA cluster general services
+hacl-gs 5301/udp # HA cluster general services
+hacl-cfg 5302/tcp # HA cluster configuration
+hacl-cfg 5302/udp # HA cluster configuration
+hacl-probe 5303/tcp # HA cluster probing
+hacl-probe 5303/udp # HA cluster probing
+hacl-local 5304/tcp
+hacl-local 5304/udp
+hacl-test 5305/tcp
+hacl-test 5305/udp
+cfengine 5308/tcp
+cfengine 5308/udp
+postgresql 5432/tcp #PostgreSQL Database
+postgresql 5432/udp #PostgreSQL Database
+rplay 5555/udp
+canna 5680/tcp #Canna (Japanese Input)
+proshareaudio 5713/tcp #proshare conf audio
+proshareaudio 5713/udp #proshare conf audio
+prosharevideo 5714/tcp #proshare conf video
+prosharevideo 5714/udp #proshare conf video
+prosharedata 5715/tcp #proshare conf data
+prosharedata 5715/udp #proshare conf data
+prosharerequest 5716/tcp #proshare conf request
+prosharerequest 5716/udp #proshare conf request
+prosharenotify 5717/tcp #proshare conf notify
+prosharenotify 5717/udp #proshare conf notify
+cvsup 5999/tcp #CVSup file transfer/John Polstra/FreeBSD
+x11 6000/tcp #6000-6063 are assigned to X Window System
+x11 6000/udp
+x11-ssh 6010/tcp #Unofficial name, for convenience
+x11-ssh 6010/udp
+softcm 6110/tcp #HP SoftBench CM
+softcm 6110/udp #HP SoftBench CM
+spc 6111/tcp #HP SoftBench Sub-Process Control
+spc 6111/udp #HP SoftBench Sub-Process Control
+meta-corp 6141/tcp #Meta Corporation License Manager
+meta-corp 6141/udp #Meta Corporation License Manager
+aspentec-lm 6142/tcp #Aspen Technology License Manager
+aspentec-lm 6142/udp #Aspen Technology License Manager
+watershed-lm 6143/tcp #Watershed License Manager
+watershed-lm 6143/udp #Watershed License Manager
+statsci1-lm 6144/tcp #StatSci License Manager - 1
+statsci1-lm 6144/udp #StatSci License Manager - 1
+statsci2-lm 6145/tcp #StatSci License Manager - 2
+statsci2-lm 6145/udp #StatSci License Manager - 2
+lonewolf-lm 6146/tcp #Lone Wolf Systems License Manager
+lonewolf-lm 6146/udp #Lone Wolf Systems License Manager
+montage-lm 6147/tcp #Montage License Manager
+montage-lm 6147/udp #Montage License Manager
+ricardo-lm 6148/tcp #Ricardo North America License Manager
+ricardo-lm 6148/udp #Ricardo North America License Manager
+xdsxdm 6558/tcp
+xdsxdm 6558/udp
+ircd 6667/tcp #Internet Relay Chat (unoffical)
+acmsoda 6969/tcp
+acmsoda 6969/udp
+afs3-fileserver 7000/tcp #file server itself
+afs3-fileserver 7000/udp #file server itself
+afs3-callback 7001/tcp #callbacks to cache managers
+afs3-callback 7001/udp #callbacks to cache managers
+afs3-prserver 7002/tcp #users & groups database
+afs3-prserver 7002/udp #users & groups database
+afs3-vlserver 7003/tcp #volume location database
+afs3-vlserver 7003/udp #volume location database
+afs3-kaserver 7004/tcp #AFS/Kerberos authentication service
+afs3-kaserver 7004/udp #AFS/Kerberos authentication service
+afs3-volser 7005/tcp #volume management server
+afs3-volser 7005/udp #volume management server
+afs3-errors 7006/tcp #error interpretation service
+afs3-errors 7006/udp #error interpretation service
+afs3-bos 7007/tcp #basic overseer process
+afs3-bos 7007/udp #basic overseer process
+afs3-update 7008/tcp #server-to-server updater
+afs3-update 7008/udp #server-to-server updater
+afs3-rmtsys 7009/tcp #remote cache manager service
+afs3-rmtsys 7009/udp #remote cache manager service
+afs3-resserver 7010/tcp #MR-AFS residence server
+afs3-resserver 7010/udp #MR-AFS residence server
+afs3-remio 7011/tcp #MR-AFS remote IO server
+afs3-remio 7011/udp #MR-AFS remote IO server
+ups-onlinet 7010/tcp #onlinet uninterruptable power supplies
+ups-onlinet 7010/udp #onlinet uninterruptable power supplies
+font-service 7100/tcp #X Font Service
+font-service 7100/udp #X Font Service
+fodms 7200/tcp #FODMS FLIP
+fodms 7200/udp #FODMS FLIP
+dlip 7201/tcp
+dlip 7201/udp
+ftp-proxy 8021/tcp # pf ftp-proxy
+spamd 8025/tcp # spamd(8)
+spamd-sync 8025/udp # spamd(8) synchronisation
+spamd-cfg 8026/tcp # spamd(8) configuration
+natd 8668/divert # Network Address Translation
+jetdirect 9100/tcp #HP JetDirect card
+man 9535/tcp
+man 9535/udp
+sd 9876/tcp #Session Director
+sd 9876/udp #Session Director
+amanda 10080/udp #Dump server control
+amandaidx 10082/tcp #Amanda indexing
+amidxtape 10083/tcp #Amanda tape indexing
+isode-dua 17007/tcp
+isode-dua 17007/udp
+biimenu 18000/tcp #Beckman Instruments, Inc.
+biimenu 18000/udp #Beckman Instruments, Inc.
+19000 19000/tcp # pfSense nat bouncing
+19000 19000/udp # pfSense nat bouncing
+19001 19001/tcp # pfSense nat bouncing
+19001 19001/udp # pfSense nat bouncing
+19002 19002/tcp # pfSense nat bouncing
+19002 19002/udp # pfSense nat bouncing
+19003 19003/tcp # pfSense nat bouncing
+19003 19003/udp # pfSense nat bouncing
+19004 19004/tcp # pfSense nat bouncing
+19004 19004/udp # pfSense nat bouncing
+19005 19005/tcp # pfSense nat bouncing
+19005 19005/udp # pfSense nat bouncing
+19006 19006/tcp # pfSense nat bouncing
+19006 19006/udp # pfSense nat bouncing
+19007 19007/tcp # pfSense nat bouncing
+19007 19007/udp # pfSense nat bouncing
+19008 19008/tcp # pfSense nat bouncing
+19008 19008/udp # pfSense nat bouncing
+19009 19009/tcp # pfSense nat bouncing
+19009 19009/udp # pfSense nat bouncing
+19010 19010/tcp # pfSense nat bouncing
+19010 19010/udp # pfSense nat bouncing
+19011 19011/tcp # pfSense nat bouncing
+19011 19011/udp # pfSense nat bouncing
+19012 19012/tcp # pfSense nat bouncing
+19012 19012/udp # pfSense nat bouncing
+19013 19013/tcp # pfSense nat bouncing
+19013 19013/udp # pfSense nat bouncing
+19014 19014/tcp # pfSense nat bouncing
+19014 19014/udp # pfSense nat bouncing
+19015 19015/tcp # pfSense nat bouncing
+19015 19015/udp # pfSense nat bouncing
+19016 19016/tcp # pfSense nat bouncing
+19016 19016/udp # pfSense nat bouncing
+19017 19017/tcp # pfSense nat bouncing
+19017 19017/udp # pfSense nat bouncing
+19018 19018/tcp # pfSense nat bouncing
+19018 19018/udp # pfSense nat bouncing
+19019 19019/tcp # pfSense nat bouncing
+19019 19019/udp # pfSense nat bouncing
+19020 19020/tcp # pfSense nat bouncing
+19020 19020/udp # pfSense nat bouncing
+19021 19021/tcp # pfSense nat bouncing
+19021 19021/udp # pfSense nat bouncing
+19022 19022/tcp # pfSense nat bouncing
+19022 19022/udp # pfSense nat bouncing
+19023 19023/tcp # pfSense nat bouncing
+19023 19023/udp # pfSense nat bouncing
+19024 19024/tcp # pfSense nat bouncing
+19024 19024/udp # pfSense nat bouncing
+19025 19025/tcp # pfSense nat bouncing
+19025 19025/udp # pfSense nat bouncing
+19026 19026/tcp # pfSense nat bouncing
+19026 19026/udp # pfSense nat bouncing
+19027 19027/tcp # pfSense nat bouncing
+19027 19027/udp # pfSense nat bouncing
+19028 19028/tcp # pfSense nat bouncing
+19028 19028/udp # pfSense nat bouncing
+19029 19029/tcp # pfSense nat bouncing
+19029 19029/udp # pfSense nat bouncing
+19030 19030/tcp # pfSense nat bouncing
+19030 19030/udp # pfSense nat bouncing
+19031 19031/tcp # pfSense nat bouncing
+19031 19031/udp # pfSense nat bouncing
+19032 19032/tcp # pfSense nat bouncing
+19032 19032/udp # pfSense nat bouncing
+19033 19033/tcp # pfSense nat bouncing
+19033 19033/udp # pfSense nat bouncing
+19034 19034/tcp # pfSense nat bouncing
+19034 19034/udp # pfSense nat bouncing
+19035 19035/tcp # pfSense nat bouncing
+19035 19035/udp # pfSense nat bouncing
+19036 19036/tcp # pfSense nat bouncing
+19036 19036/udp # pfSense nat bouncing
+19037 19037/tcp # pfSense nat bouncing
+19037 19037/udp # pfSense nat bouncing
+19038 19038/tcp # pfSense nat bouncing
+19038 19038/udp # pfSense nat bouncing
+19039 19039/tcp # pfSense nat bouncing
+19039 19039/udp # pfSense nat bouncing
+19040 19040/tcp # pfSense nat bouncing
+19040 19040/udp # pfSense nat bouncing
+19041 19041/tcp # pfSense nat bouncing
+19041 19041/udp # pfSense nat bouncing
+19042 19042/tcp # pfSense nat bouncing
+19042 19042/udp # pfSense nat bouncing
+19043 19043/tcp # pfSense nat bouncing
+19043 19043/udp # pfSense nat bouncing
+19044 19044/tcp # pfSense nat bouncing
+19044 19044/udp # pfSense nat bouncing
+19045 19045/tcp # pfSense nat bouncing
+19045 19045/udp # pfSense nat bouncing
+19046 19046/tcp # pfSense nat bouncing
+19046 19046/udp # pfSense nat bouncing
+19047 19047/tcp # pfSense nat bouncing
+19047 19047/udp # pfSense nat bouncing
+19048 19048/tcp # pfSense nat bouncing
+19048 19048/udp # pfSense nat bouncing
+19049 19049/tcp # pfSense nat bouncing
+19049 19049/udp # pfSense nat bouncing
+19050 19050/tcp # pfSense nat bouncing
+19050 19050/udp # pfSense nat bouncing
+19051 19051/tcp # pfSense nat bouncing
+19051 19051/udp # pfSense nat bouncing
+19052 19052/tcp # pfSense nat bouncing
+19052 19052/udp # pfSense nat bouncing
+19053 19053/tcp # pfSense nat bouncing
+19053 19053/udp # pfSense nat bouncing
+19054 19054/tcp # pfSense nat bouncing
+19054 19054/udp # pfSense nat bouncing
+19055 19055/tcp # pfSense nat bouncing
+19055 19055/udp # pfSense nat bouncing
+19056 19056/tcp # pfSense nat bouncing
+19056 19056/udp # pfSense nat bouncing
+19057 19057/tcp # pfSense nat bouncing
+19057 19057/udp # pfSense nat bouncing
+19058 19058/tcp # pfSense nat bouncing
+19058 19058/udp # pfSense nat bouncing
+19059 19059/tcp # pfSense nat bouncing
+19059 19059/udp # pfSense nat bouncing
+19060 19060/tcp # pfSense nat bouncing
+19060 19060/udp # pfSense nat bouncing
+19061 19061/tcp # pfSense nat bouncing
+19061 19061/udp # pfSense nat bouncing
+19062 19062/tcp # pfSense nat bouncing
+19062 19062/udp # pfSense nat bouncing
+19063 19063/tcp # pfSense nat bouncing
+19063 19063/udp # pfSense nat bouncing
+19064 19064/tcp # pfSense nat bouncing
+19064 19064/udp # pfSense nat bouncing
+19065 19065/tcp # pfSense nat bouncing
+19065 19065/udp # pfSense nat bouncing
+19066 19066/tcp # pfSense nat bouncing
+19066 19066/udp # pfSense nat bouncing
+19067 19067/tcp # pfSense nat bouncing
+19067 19067/udp # pfSense nat bouncing
+19068 19068/tcp # pfSense nat bouncing
+19068 19068/udp # pfSense nat bouncing
+19069 19069/tcp # pfSense nat bouncing
+19069 19069/udp # pfSense nat bouncing
+19070 19070/tcp # pfSense nat bouncing
+19070 19070/udp # pfSense nat bouncing
+19071 19071/tcp # pfSense nat bouncing
+19071 19071/udp # pfSense nat bouncing
+19072 19072/tcp # pfSense nat bouncing
+19072 19072/udp # pfSense nat bouncing
+19073 19073/tcp # pfSense nat bouncing
+19073 19073/udp # pfSense nat bouncing
+19074 19074/tcp # pfSense nat bouncing
+19074 19074/udp # pfSense nat bouncing
+19075 19075/tcp # pfSense nat bouncing
+19075 19075/udp # pfSense nat bouncing
+19076 19076/tcp # pfSense nat bouncing
+19076 19076/udp # pfSense nat bouncing
+19077 19077/tcp # pfSense nat bouncing
+19077 19077/udp # pfSense nat bouncing
+19078 19078/tcp # pfSense nat bouncing
+19078 19078/udp # pfSense nat bouncing
+19079 19079/tcp # pfSense nat bouncing
+19079 19079/udp # pfSense nat bouncing
+19080 19080/tcp # pfSense nat bouncing
+19080 19080/udp # pfSense nat bouncing
+19081 19081/tcp # pfSense nat bouncing
+19081 19081/udp # pfSense nat bouncing
+19082 19082/tcp # pfSense nat bouncing
+19082 19082/udp # pfSense nat bouncing
+19083 19083/tcp # pfSense nat bouncing
+19083 19083/udp # pfSense nat bouncing
+19084 19084/tcp # pfSense nat bouncing
+19084 19084/udp # pfSense nat bouncing
+19085 19085/tcp # pfSense nat bouncing
+19085 19085/udp # pfSense nat bouncing
+19086 19086/tcp # pfSense nat bouncing
+19086 19086/udp # pfSense nat bouncing
+19087 19087/tcp # pfSense nat bouncing
+19087 19087/udp # pfSense nat bouncing
+19088 19088/tcp # pfSense nat bouncing
+19088 19088/udp # pfSense nat bouncing
+19089 19089/tcp # pfSense nat bouncing
+19089 19089/udp # pfSense nat bouncing
+19090 19090/tcp # pfSense nat bouncing
+19090 19090/udp # pfSense nat bouncing
+19091 19091/tcp # pfSense nat bouncing
+19091 19091/udp # pfSense nat bouncing
+19092 19092/tcp # pfSense nat bouncing
+19092 19092/udp # pfSense nat bouncing
+19093 19093/tcp # pfSense nat bouncing
+19093 19093/udp # pfSense nat bouncing
+19094 19094/tcp # pfSense nat bouncing
+19094 19094/udp # pfSense nat bouncing
+19095 19095/tcp # pfSense nat bouncing
+19095 19095/udp # pfSense nat bouncing
+19096 19096/tcp # pfSense nat bouncing
+19096 19096/udp # pfSense nat bouncing
+19097 19097/tcp # pfSense nat bouncing
+19097 19097/udp # pfSense nat bouncing
+19098 19098/tcp # pfSense nat bouncing
+19098 19098/udp # pfSense nat bouncing
+19099 19099/tcp # pfSense nat bouncing
+19099 19099/udp # pfSense nat bouncing
+19100 19100/tcp # pfSense nat bouncing
+19100 19100/udp # pfSense nat bouncing
+19101 19101/tcp # pfSense nat bouncing
+19101 19101/udp # pfSense nat bouncing
+19102 19102/tcp # pfSense nat bouncing
+19102 19102/udp # pfSense nat bouncing
+19103 19103/tcp # pfSense nat bouncing
+19103 19103/udp # pfSense nat bouncing
+19104 19104/tcp # pfSense nat bouncing
+19104 19104/udp # pfSense nat bouncing
+19105 19105/tcp # pfSense nat bouncing
+19105 19105/udp # pfSense nat bouncing
+19106 19106/tcp # pfSense nat bouncing
+19106 19106/udp # pfSense nat bouncing
+19107 19107/tcp # pfSense nat bouncing
+19107 19107/udp # pfSense nat bouncing
+19108 19108/tcp # pfSense nat bouncing
+19108 19108/udp # pfSense nat bouncing
+19109 19109/tcp # pfSense nat bouncing
+19109 19109/udp # pfSense nat bouncing
+19110 19110/tcp # pfSense nat bouncing
+19110 19110/udp # pfSense nat bouncing
+19111 19111/tcp # pfSense nat bouncing
+19111 19111/udp # pfSense nat bouncing
+19112 19112/tcp # pfSense nat bouncing
+19112 19112/udp # pfSense nat bouncing
+19113 19113/tcp # pfSense nat bouncing
+19113 19113/udp # pfSense nat bouncing
+19114 19114/tcp # pfSense nat bouncing
+19114 19114/udp # pfSense nat bouncing
+19115 19115/tcp # pfSense nat bouncing
+19115 19115/udp # pfSense nat bouncing
+19116 19116/tcp # pfSense nat bouncing
+19116 19116/udp # pfSense nat bouncing
+19117 19117/tcp # pfSense nat bouncing
+19117 19117/udp # pfSense nat bouncing
+19118 19118/tcp # pfSense nat bouncing
+19118 19118/udp # pfSense nat bouncing
+19119 19119/tcp # pfSense nat bouncing
+19119 19119/udp # pfSense nat bouncing
+19120 19120/tcp # pfSense nat bouncing
+19120 19120/udp # pfSense nat bouncing
+19121 19121/tcp # pfSense nat bouncing
+19121 19121/udp # pfSense nat bouncing
+19122 19122/tcp # pfSense nat bouncing
+19122 19122/udp # pfSense nat bouncing
+19123 19123/tcp # pfSense nat bouncing
+19123 19123/udp # pfSense nat bouncing
+19124 19124/tcp # pfSense nat bouncing
+19124 19124/udp # pfSense nat bouncing
+19125 19125/tcp # pfSense nat bouncing
+19125 19125/udp # pfSense nat bouncing
+19126 19126/tcp # pfSense nat bouncing
+19126 19126/udp # pfSense nat bouncing
+19127 19127/tcp # pfSense nat bouncing
+19127 19127/udp # pfSense nat bouncing
+19128 19128/tcp # pfSense nat bouncing
+19128 19128/udp # pfSense nat bouncing
+19129 19129/tcp # pfSense nat bouncing
+19129 19129/udp # pfSense nat bouncing
+19130 19130/tcp # pfSense nat bouncing
+19130 19130/udp # pfSense nat bouncing
+19131 19131/tcp # pfSense nat bouncing
+19131 19131/udp # pfSense nat bouncing
+19132 19132/tcp # pfSense nat bouncing
+19132 19132/udp # pfSense nat bouncing
+19133 19133/tcp # pfSense nat bouncing
+19133 19133/udp # pfSense nat bouncing
+19134 19134/tcp # pfSense nat bouncing
+19134 19134/udp # pfSense nat bouncing
+19135 19135/tcp # pfSense nat bouncing
+19135 19135/udp # pfSense nat bouncing
+19136 19136/tcp # pfSense nat bouncing
+19136 19136/udp # pfSense nat bouncing
+19137 19137/tcp # pfSense nat bouncing
+19137 19137/udp # pfSense nat bouncing
+19138 19138/tcp # pfSense nat bouncing
+19138 19138/udp # pfSense nat bouncing
+19139 19139/tcp # pfSense nat bouncing
+19139 19139/udp # pfSense nat bouncing
+19140 19140/tcp # pfSense nat bouncing
+19140 19140/udp # pfSense nat bouncing
+19141 19141/tcp # pfSense nat bouncing
+19141 19141/udp # pfSense nat bouncing
+19142 19142/tcp # pfSense nat bouncing
+19142 19142/udp # pfSense nat bouncing
+19143 19143/tcp # pfSense nat bouncing
+19143 19143/udp # pfSense nat bouncing
+19144 19144/tcp # pfSense nat bouncing
+19144 19144/udp # pfSense nat bouncing
+19145 19145/tcp # pfSense nat bouncing
+19145 19145/udp # pfSense nat bouncing
+19146 19146/tcp # pfSense nat bouncing
+19146 19146/udp # pfSense nat bouncing
+19147 19147/tcp # pfSense nat bouncing
+19147 19147/udp # pfSense nat bouncing
+19148 19148/tcp # pfSense nat bouncing
+19148 19148/udp # pfSense nat bouncing
+19149 19149/tcp # pfSense nat bouncing
+19149 19149/udp # pfSense nat bouncing
+19150 19150/tcp # pfSense nat bouncing
+19150 19150/udp # pfSense nat bouncing
+19151 19151/tcp # pfSense nat bouncing
+19151 19151/udp # pfSense nat bouncing
+19152 19152/tcp # pfSense nat bouncing
+19152 19152/udp # pfSense nat bouncing
+19153 19153/tcp # pfSense nat bouncing
+19153 19153/udp # pfSense nat bouncing
+19154 19154/tcp # pfSense nat bouncing
+19154 19154/udp # pfSense nat bouncing
+19155 19155/tcp # pfSense nat bouncing
+19155 19155/udp # pfSense nat bouncing
+19156 19156/tcp # pfSense nat bouncing
+19156 19156/udp # pfSense nat bouncing
+19157 19157/tcp # pfSense nat bouncing
+19157 19157/udp # pfSense nat bouncing
+19158 19158/tcp # pfSense nat bouncing
+19158 19158/udp # pfSense nat bouncing
+19159 19159/tcp # pfSense nat bouncing
+19159 19159/udp # pfSense nat bouncing
+19160 19160/tcp # pfSense nat bouncing
+19160 19160/udp # pfSense nat bouncing
+19161 19161/tcp # pfSense nat bouncing
+19161 19161/udp # pfSense nat bouncing
+19162 19162/tcp # pfSense nat bouncing
+19162 19162/udp # pfSense nat bouncing
+19163 19163/tcp # pfSense nat bouncing
+19163 19163/udp # pfSense nat bouncing
+19164 19164/tcp # pfSense nat bouncing
+19164 19164/udp # pfSense nat bouncing
+19165 19165/tcp # pfSense nat bouncing
+19165 19165/udp # pfSense nat bouncing
+19166 19166/tcp # pfSense nat bouncing
+19166 19166/udp # pfSense nat bouncing
+19167 19167/tcp # pfSense nat bouncing
+19167 19167/udp # pfSense nat bouncing
+19168 19168/tcp # pfSense nat bouncing
+19168 19168/udp # pfSense nat bouncing
+19169 19169/tcp # pfSense nat bouncing
+19169 19169/udp # pfSense nat bouncing
+19170 19170/tcp # pfSense nat bouncing
+19170 19170/udp # pfSense nat bouncing
+19171 19171/tcp # pfSense nat bouncing
+19171 19171/udp # pfSense nat bouncing
+19172 19172/tcp # pfSense nat bouncing
+19172 19172/udp # pfSense nat bouncing
+19173 19173/tcp # pfSense nat bouncing
+19173 19173/udp # pfSense nat bouncing
+19174 19174/tcp # pfSense nat bouncing
+19174 19174/udp # pfSense nat bouncing
+19175 19175/tcp # pfSense nat bouncing
+19175 19175/udp # pfSense nat bouncing
+19176 19176/tcp # pfSense nat bouncing
+19176 19176/udp # pfSense nat bouncing
+19177 19177/tcp # pfSense nat bouncing
+19177 19177/udp # pfSense nat bouncing
+19178 19178/tcp # pfSense nat bouncing
+19178 19178/udp # pfSense nat bouncing
+19179 19179/tcp # pfSense nat bouncing
+19179 19179/udp # pfSense nat bouncing
+19180 19180/tcp # pfSense nat bouncing
+19180 19180/udp # pfSense nat bouncing
+19181 19181/tcp # pfSense nat bouncing
+19181 19181/udp # pfSense nat bouncing
+19182 19182/tcp # pfSense nat bouncing
+19182 19182/udp # pfSense nat bouncing
+19183 19183/tcp # pfSense nat bouncing
+19183 19183/udp # pfSense nat bouncing
+19184 19184/tcp # pfSense nat bouncing
+19184 19184/udp # pfSense nat bouncing
+19185 19185/tcp # pfSense nat bouncing
+19185 19185/udp # pfSense nat bouncing
+19186 19186/tcp # pfSense nat bouncing
+19186 19186/udp # pfSense nat bouncing
+19187 19187/tcp # pfSense nat bouncing
+19187 19187/udp # pfSense nat bouncing
+19188 19188/tcp # pfSense nat bouncing
+19188 19188/udp # pfSense nat bouncing
+19189 19189/tcp # pfSense nat bouncing
+19189 19189/udp # pfSense nat bouncing
+19190 19190/tcp # pfSense nat bouncing
+19190 19190/udp # pfSense nat bouncing
+19191 19191/tcp # pfSense nat bouncing
+19191 19191/udp # pfSense nat bouncing
+19192 19192/tcp # pfSense nat bouncing
+19192 19192/udp # pfSense nat bouncing
+19193 19193/tcp # pfSense nat bouncing
+19193 19193/udp # pfSense nat bouncing
+19194 19194/tcp # pfSense nat bouncing
+19194 19194/udp # pfSense nat bouncing
+19195 19195/tcp # pfSense nat bouncing
+19195 19195/udp # pfSense nat bouncing
+19196 19196/tcp # pfSense nat bouncing
+19196 19196/udp # pfSense nat bouncing
+19197 19197/tcp # pfSense nat bouncing
+19197 19197/udp # pfSense nat bouncing
+19198 19198/tcp # pfSense nat bouncing
+19198 19198/udp # pfSense nat bouncing
+19199 19199/tcp # pfSense nat bouncing
+19199 19199/udp # pfSense nat bouncing
+19200 19200/tcp # pfSense nat bouncing
+19200 19200/udp # pfSense nat bouncing
+19201 19201/tcp # pfSense nat bouncing
+19201 19201/udp # pfSense nat bouncing
+19202 19202/tcp # pfSense nat bouncing
+19202 19202/udp # pfSense nat bouncing
+19203 19203/tcp # pfSense nat bouncing
+19203 19203/udp # pfSense nat bouncing
+19204 19204/tcp # pfSense nat bouncing
+19204 19204/udp # pfSense nat bouncing
+19205 19205/tcp # pfSense nat bouncing
+19205 19205/udp # pfSense nat bouncing
+19206 19206/tcp # pfSense nat bouncing
+19206 19206/udp # pfSense nat bouncing
+19207 19207/tcp # pfSense nat bouncing
+19207 19207/udp # pfSense nat bouncing
+19208 19208/tcp # pfSense nat bouncing
+19208 19208/udp # pfSense nat bouncing
+19209 19209/tcp # pfSense nat bouncing
+19209 19209/udp # pfSense nat bouncing
+19210 19210/tcp # pfSense nat bouncing
+19210 19210/udp # pfSense nat bouncing
+19211 19211/tcp # pfSense nat bouncing
+19211 19211/udp # pfSense nat bouncing
+19212 19212/tcp # pfSense nat bouncing
+19212 19212/udp # pfSense nat bouncing
+19213 19213/tcp # pfSense nat bouncing
+19213 19213/udp # pfSense nat bouncing
+19214 19214/tcp # pfSense nat bouncing
+19214 19214/udp # pfSense nat bouncing
+19215 19215/tcp # pfSense nat bouncing
+19215 19215/udp # pfSense nat bouncing
+19216 19216/tcp # pfSense nat bouncing
+19216 19216/udp # pfSense nat bouncing
+19217 19217/tcp # pfSense nat bouncing
+19217 19217/udp # pfSense nat bouncing
+19218 19218/tcp # pfSense nat bouncing
+19218 19218/udp # pfSense nat bouncing
+19219 19219/tcp # pfSense nat bouncing
+19219 19219/udp # pfSense nat bouncing
+19220 19220/tcp # pfSense nat bouncing
+19220 19220/udp # pfSense nat bouncing
+19221 19221/tcp # pfSense nat bouncing
+19221 19221/udp # pfSense nat bouncing
+19222 19222/tcp # pfSense nat bouncing
+19222 19222/udp # pfSense nat bouncing
+19223 19223/tcp # pfSense nat bouncing
+19223 19223/udp # pfSense nat bouncing
+19224 19224/tcp # pfSense nat bouncing
+19224 19224/udp # pfSense nat bouncing
+19225 19225/tcp # pfSense nat bouncing
+19225 19225/udp # pfSense nat bouncing
+19226 19226/tcp # pfSense nat bouncing
+19226 19226/udp # pfSense nat bouncing
+19227 19227/tcp # pfSense nat bouncing
+19227 19227/udp # pfSense nat bouncing
+19228 19228/tcp # pfSense nat bouncing
+19228 19228/udp # pfSense nat bouncing
+19229 19229/tcp # pfSense nat bouncing
+19229 19229/udp # pfSense nat bouncing
+19230 19230/tcp # pfSense nat bouncing
+19230 19230/udp # pfSense nat bouncing
+19231 19231/tcp # pfSense nat bouncing
+19231 19231/udp # pfSense nat bouncing
+19232 19232/tcp # pfSense nat bouncing
+19232 19232/udp # pfSense nat bouncing
+19233 19233/tcp # pfSense nat bouncing
+19233 19233/udp # pfSense nat bouncing
+19234 19234/tcp # pfSense nat bouncing
+19234 19234/udp # pfSense nat bouncing
+19235 19235/tcp # pfSense nat bouncing
+19235 19235/udp # pfSense nat bouncing
+19236 19236/tcp # pfSense nat bouncing
+19236 19236/udp # pfSense nat bouncing
+19237 19237/tcp # pfSense nat bouncing
+19237 19237/udp # pfSense nat bouncing
+19238 19238/tcp # pfSense nat bouncing
+19238 19238/udp # pfSense nat bouncing
+19239 19239/tcp # pfSense nat bouncing
+19239 19239/udp # pfSense nat bouncing
+19240 19240/tcp # pfSense nat bouncing
+19240 19240/udp # pfSense nat bouncing
+19241 19241/tcp # pfSense nat bouncing
+19241 19241/udp # pfSense nat bouncing
+19242 19242/tcp # pfSense nat bouncing
+19242 19242/udp # pfSense nat bouncing
+19243 19243/tcp # pfSense nat bouncing
+19243 19243/udp # pfSense nat bouncing
+19244 19244/tcp # pfSense nat bouncing
+19244 19244/udp # pfSense nat bouncing
+19245 19245/tcp # pfSense nat bouncing
+19245 19245/udp # pfSense nat bouncing
+19246 19246/tcp # pfSense nat bouncing
+19246 19246/udp # pfSense nat bouncing
+19247 19247/tcp # pfSense nat bouncing
+19247 19247/udp # pfSense nat bouncing
+19248 19248/tcp # pfSense nat bouncing
+19248 19248/udp # pfSense nat bouncing
+19249 19249/tcp # pfSense nat bouncing
+19249 19249/udp # pfSense nat bouncing
+19250 19250/tcp # pfSense nat bouncing
+19250 19250/udp # pfSense nat bouncing
+19251 19251/tcp # pfSense nat bouncing
+19251 19251/udp # pfSense nat bouncing
+19252 19252/tcp # pfSense nat bouncing
+19252 19252/udp # pfSense nat bouncing
+19253 19253/tcp # pfSense nat bouncing
+19253 19253/udp # pfSense nat bouncing
+19254 19254/tcp # pfSense nat bouncing
+19254 19254/udp # pfSense nat bouncing
+19255 19255/tcp # pfSense nat bouncing
+19255 19255/udp # pfSense nat bouncing
+19256 19256/tcp # pfSense nat bouncing
+19256 19256/udp # pfSense nat bouncing
+19257 19257/tcp # pfSense nat bouncing
+19257 19257/udp # pfSense nat bouncing
+19258 19258/tcp # pfSense nat bouncing
+19258 19258/udp # pfSense nat bouncing
+19259 19259/tcp # pfSense nat bouncing
+19259 19259/udp # pfSense nat bouncing
+19260 19260/tcp # pfSense nat bouncing
+19260 19260/udp # pfSense nat bouncing
+19261 19261/tcp # pfSense nat bouncing
+19261 19261/udp # pfSense nat bouncing
+19262 19262/tcp # pfSense nat bouncing
+19262 19262/udp # pfSense nat bouncing
+19263 19263/tcp # pfSense nat bouncing
+19263 19263/udp # pfSense nat bouncing
+19264 19264/tcp # pfSense nat bouncing
+19264 19264/udp # pfSense nat bouncing
+19265 19265/tcp # pfSense nat bouncing
+19265 19265/udp # pfSense nat bouncing
+19266 19266/tcp # pfSense nat bouncing
+19266 19266/udp # pfSense nat bouncing
+19267 19267/tcp # pfSense nat bouncing
+19267 19267/udp # pfSense nat bouncing
+19268 19268/tcp # pfSense nat bouncing
+19268 19268/udp # pfSense nat bouncing
+19269 19269/tcp # pfSense nat bouncing
+19269 19269/udp # pfSense nat bouncing
+19270 19270/tcp # pfSense nat bouncing
+19270 19270/udp # pfSense nat bouncing
+19271 19271/tcp # pfSense nat bouncing
+19271 19271/udp # pfSense nat bouncing
+19272 19272/tcp # pfSense nat bouncing
+19272 19272/udp # pfSense nat bouncing
+19273 19273/tcp # pfSense nat bouncing
+19273 19273/udp # pfSense nat bouncing
+19274 19274/tcp # pfSense nat bouncing
+19274 19274/udp # pfSense nat bouncing
+19275 19275/tcp # pfSense nat bouncing
+19275 19275/udp # pfSense nat bouncing
+19276 19276/tcp # pfSense nat bouncing
+19276 19276/udp # pfSense nat bouncing
+19277 19277/tcp # pfSense nat bouncing
+19277 19277/udp # pfSense nat bouncing
+19278 19278/tcp # pfSense nat bouncing
+19278 19278/udp # pfSense nat bouncing
+19279 19279/tcp # pfSense nat bouncing
+19279 19279/udp # pfSense nat bouncing
+19280 19280/tcp # pfSense nat bouncing
+19280 19280/udp # pfSense nat bouncing
+19281 19281/tcp # pfSense nat bouncing
+19281 19281/udp # pfSense nat bouncing
+19282 19282/tcp # pfSense nat bouncing
+19282 19282/udp # pfSense nat bouncing
+19283 19283/tcp # pfSense nat bouncing
+19283 19283/udp # pfSense nat bouncing
+19284 19284/tcp # pfSense nat bouncing
+19284 19284/udp # pfSense nat bouncing
+19285 19285/tcp # pfSense nat bouncing
+19285 19285/udp # pfSense nat bouncing
+19286 19286/tcp # pfSense nat bouncing
+19286 19286/udp # pfSense nat bouncing
+19287 19287/tcp # pfSense nat bouncing
+19287 19287/udp # pfSense nat bouncing
+19288 19288/tcp # pfSense nat bouncing
+19288 19288/udp # pfSense nat bouncing
+19289 19289/tcp # pfSense nat bouncing
+19289 19289/udp # pfSense nat bouncing
+19290 19290/tcp # pfSense nat bouncing
+19290 19290/udp # pfSense nat bouncing
+19291 19291/tcp # pfSense nat bouncing
+19291 19291/udp # pfSense nat bouncing
+19292 19292/tcp # pfSense nat bouncing
+19292 19292/udp # pfSense nat bouncing
+19293 19293/tcp # pfSense nat bouncing
+19293 19293/udp # pfSense nat bouncing
+19294 19294/tcp # pfSense nat bouncing
+19294 19294/udp # pfSense nat bouncing
+19295 19295/tcp # pfSense nat bouncing
+19295 19295/udp # pfSense nat bouncing
+19296 19296/tcp # pfSense nat bouncing
+19296 19296/udp # pfSense nat bouncing
+19297 19297/tcp # pfSense nat bouncing
+19297 19297/udp # pfSense nat bouncing
+19298 19298/tcp # pfSense nat bouncing
+19298 19298/udp # pfSense nat bouncing
+19299 19299/tcp # pfSense nat bouncing
+19299 19299/udp # pfSense nat bouncing
+19300 19300/tcp # pfSense nat bouncing
+19300 19300/udp # pfSense nat bouncing
+19301 19301/tcp # pfSense nat bouncing
+19301 19301/udp # pfSense nat bouncing
+19302 19302/tcp # pfSense nat bouncing
+19302 19302/udp # pfSense nat bouncing
+19303 19303/tcp # pfSense nat bouncing
+19303 19303/udp # pfSense nat bouncing
+19304 19304/tcp # pfSense nat bouncing
+19304 19304/udp # pfSense nat bouncing
+19305 19305/tcp # pfSense nat bouncing
+19305 19305/udp # pfSense nat bouncing
+19306 19306/tcp # pfSense nat bouncing
+19306 19306/udp # pfSense nat bouncing
+19307 19307/tcp # pfSense nat bouncing
+19307 19307/udp # pfSense nat bouncing
+19308 19308/tcp # pfSense nat bouncing
+19308 19308/udp # pfSense nat bouncing
+19309 19309/tcp # pfSense nat bouncing
+19309 19309/udp # pfSense nat bouncing
+19310 19310/tcp # pfSense nat bouncing
+19310 19310/udp # pfSense nat bouncing
+19311 19311/tcp # pfSense nat bouncing
+19311 19311/udp # pfSense nat bouncing
+19312 19312/tcp # pfSense nat bouncing
+19312 19312/udp # pfSense nat bouncing
+19313 19313/tcp # pfSense nat bouncing
+19313 19313/udp # pfSense nat bouncing
+19314 19314/tcp # pfSense nat bouncing
+19314 19314/udp # pfSense nat bouncing
+19315 19315/tcp # pfSense nat bouncing
+19315 19315/udp # pfSense nat bouncing
+19316 19316/tcp # pfSense nat bouncing
+19316 19316/udp # pfSense nat bouncing
+19317 19317/tcp # pfSense nat bouncing
+19317 19317/udp # pfSense nat bouncing
+19318 19318/tcp # pfSense nat bouncing
+19318 19318/udp # pfSense nat bouncing
+19319 19319/tcp # pfSense nat bouncing
+19319 19319/udp # pfSense nat bouncing
+19320 19320/tcp # pfSense nat bouncing
+19320 19320/udp # pfSense nat bouncing
+19321 19321/tcp # pfSense nat bouncing
+19321 19321/udp # pfSense nat bouncing
+19322 19322/tcp # pfSense nat bouncing
+19322 19322/udp # pfSense nat bouncing
+19323 19323/tcp # pfSense nat bouncing
+19323 19323/udp # pfSense nat bouncing
+19324 19324/tcp # pfSense nat bouncing
+19324 19324/udp # pfSense nat bouncing
+19325 19325/tcp # pfSense nat bouncing
+19325 19325/udp # pfSense nat bouncing
+19326 19326/tcp # pfSense nat bouncing
+19326 19326/udp # pfSense nat bouncing
+19327 19327/tcp # pfSense nat bouncing
+19327 19327/udp # pfSense nat bouncing
+19328 19328/tcp # pfSense nat bouncing
+19328 19328/udp # pfSense nat bouncing
+19329 19329/tcp # pfSense nat bouncing
+19329 19329/udp # pfSense nat bouncing
+19330 19330/tcp # pfSense nat bouncing
+19330 19330/udp # pfSense nat bouncing
+19331 19331/tcp # pfSense nat bouncing
+19331 19331/udp # pfSense nat bouncing
+19332 19332/tcp # pfSense nat bouncing
+19332 19332/udp # pfSense nat bouncing
+19333 19333/tcp # pfSense nat bouncing
+19333 19333/udp # pfSense nat bouncing
+19334 19334/tcp # pfSense nat bouncing
+19334 19334/udp # pfSense nat bouncing
+19335 19335/tcp # pfSense nat bouncing
+19335 19335/udp # pfSense nat bouncing
+19336 19336/tcp # pfSense nat bouncing
+19336 19336/udp # pfSense nat bouncing
+19337 19337/tcp # pfSense nat bouncing
+19337 19337/udp # pfSense nat bouncing
+19338 19338/tcp # pfSense nat bouncing
+19338 19338/udp # pfSense nat bouncing
+19339 19339/tcp # pfSense nat bouncing
+19339 19339/udp # pfSense nat bouncing
+19340 19340/tcp # pfSense nat bouncing
+19340 19340/udp # pfSense nat bouncing
+19341 19341/tcp # pfSense nat bouncing
+19341 19341/udp # pfSense nat bouncing
+19342 19342/tcp # pfSense nat bouncing
+19342 19342/udp # pfSense nat bouncing
+19343 19343/tcp # pfSense nat bouncing
+19343 19343/udp # pfSense nat bouncing
+19344 19344/tcp # pfSense nat bouncing
+19344 19344/udp # pfSense nat bouncing
+19345 19345/tcp # pfSense nat bouncing
+19345 19345/udp # pfSense nat bouncing
+19346 19346/tcp # pfSense nat bouncing
+19346 19346/udp # pfSense nat bouncing
+19347 19347/tcp # pfSense nat bouncing
+19347 19347/udp # pfSense nat bouncing
+19348 19348/tcp # pfSense nat bouncing
+19348 19348/udp # pfSense nat bouncing
+19349 19349/tcp # pfSense nat bouncing
+19349 19349/udp # pfSense nat bouncing
+19350 19350/tcp # pfSense nat bouncing
+19350 19350/udp # pfSense nat bouncing
+19351 19351/tcp # pfSense nat bouncing
+19351 19351/udp # pfSense nat bouncing
+19352 19352/tcp # pfSense nat bouncing
+19352 19352/udp # pfSense nat bouncing
+19353 19353/tcp # pfSense nat bouncing
+19353 19353/udp # pfSense nat bouncing
+19354 19354/tcp # pfSense nat bouncing
+19354 19354/udp # pfSense nat bouncing
+19355 19355/tcp # pfSense nat bouncing
+19355 19355/udp # pfSense nat bouncing
+19356 19356/tcp # pfSense nat bouncing
+19356 19356/udp # pfSense nat bouncing
+19357 19357/tcp # pfSense nat bouncing
+19357 19357/udp # pfSense nat bouncing
+19358 19358/tcp # pfSense nat bouncing
+19358 19358/udp # pfSense nat bouncing
+19359 19359/tcp # pfSense nat bouncing
+19359 19359/udp # pfSense nat bouncing
+19360 19360/tcp # pfSense nat bouncing
+19360 19360/udp # pfSense nat bouncing
+19361 19361/tcp # pfSense nat bouncing
+19361 19361/udp # pfSense nat bouncing
+19362 19362/tcp # pfSense nat bouncing
+19362 19362/udp # pfSense nat bouncing
+19363 19363/tcp # pfSense nat bouncing
+19363 19363/udp # pfSense nat bouncing
+19364 19364/tcp # pfSense nat bouncing
+19364 19364/udp # pfSense nat bouncing
+19365 19365/tcp # pfSense nat bouncing
+19365 19365/udp # pfSense nat bouncing
+19366 19366/tcp # pfSense nat bouncing
+19366 19366/udp # pfSense nat bouncing
+19367 19367/tcp # pfSense nat bouncing
+19367 19367/udp # pfSense nat bouncing
+19368 19368/tcp # pfSense nat bouncing
+19368 19368/udp # pfSense nat bouncing
+19369 19369/tcp # pfSense nat bouncing
+19369 19369/udp # pfSense nat bouncing
+19370 19370/tcp # pfSense nat bouncing
+19370 19370/udp # pfSense nat bouncing
+19371 19371/tcp # pfSense nat bouncing
+19371 19371/udp # pfSense nat bouncing
+19372 19372/tcp # pfSense nat bouncing
+19372 19372/udp # pfSense nat bouncing
+19373 19373/tcp # pfSense nat bouncing
+19373 19373/udp # pfSense nat bouncing
+19374 19374/tcp # pfSense nat bouncing
+19374 19374/udp # pfSense nat bouncing
+19375 19375/tcp # pfSense nat bouncing
+19375 19375/udp # pfSense nat bouncing
+19376 19376/tcp # pfSense nat bouncing
+19376 19376/udp # pfSense nat bouncing
+19377 19377/tcp # pfSense nat bouncing
+19377 19377/udp # pfSense nat bouncing
+19378 19378/tcp # pfSense nat bouncing
+19378 19378/udp # pfSense nat bouncing
+19379 19379/tcp # pfSense nat bouncing
+19379 19379/udp # pfSense nat bouncing
+19380 19380/tcp # pfSense nat bouncing
+19380 19380/udp # pfSense nat bouncing
+19381 19381/tcp # pfSense nat bouncing
+19381 19381/udp # pfSense nat bouncing
+19382 19382/tcp # pfSense nat bouncing
+19382 19382/udp # pfSense nat bouncing
+19383 19383/tcp # pfSense nat bouncing
+19383 19383/udp # pfSense nat bouncing
+19384 19384/tcp # pfSense nat bouncing
+19384 19384/udp # pfSense nat bouncing
+19385 19385/tcp # pfSense nat bouncing
+19385 19385/udp # pfSense nat bouncing
+19386 19386/tcp # pfSense nat bouncing
+19386 19386/udp # pfSense nat bouncing
+19387 19387/tcp # pfSense nat bouncing
+19387 19387/udp # pfSense nat bouncing
+19388 19388/tcp # pfSense nat bouncing
+19388 19388/udp # pfSense nat bouncing
+19389 19389/tcp # pfSense nat bouncing
+19389 19389/udp # pfSense nat bouncing
+19390 19390/tcp # pfSense nat bouncing
+19390 19390/udp # pfSense nat bouncing
+19391 19391/tcp # pfSense nat bouncing
+19391 19391/udp # pfSense nat bouncing
+19392 19392/tcp # pfSense nat bouncing
+19392 19392/udp # pfSense nat bouncing
+19393 19393/tcp # pfSense nat bouncing
+19393 19393/udp # pfSense nat bouncing
+19394 19394/tcp # pfSense nat bouncing
+19394 19394/udp # pfSense nat bouncing
+19395 19395/tcp # pfSense nat bouncing
+19395 19395/udp # pfSense nat bouncing
+19396 19396/tcp # pfSense nat bouncing
+19396 19396/udp # pfSense nat bouncing
+19397 19397/tcp # pfSense nat bouncing
+19397 19397/udp # pfSense nat bouncing
+19398 19398/tcp # pfSense nat bouncing
+19398 19398/udp # pfSense nat bouncing
+19399 19399/tcp # pfSense nat bouncing
+19399 19399/udp # pfSense nat bouncing
+19400 19400/tcp # pfSense nat bouncing
+19400 19400/udp # pfSense nat bouncing
+19401 19401/tcp # pfSense nat bouncing
+19401 19401/udp # pfSense nat bouncing
+19402 19402/tcp # pfSense nat bouncing
+19402 19402/udp # pfSense nat bouncing
+19403 19403/tcp # pfSense nat bouncing
+19403 19403/udp # pfSense nat bouncing
+19404 19404/tcp # pfSense nat bouncing
+19404 19404/udp # pfSense nat bouncing
+19405 19405/tcp # pfSense nat bouncing
+19405 19405/udp # pfSense nat bouncing
+19406 19406/tcp # pfSense nat bouncing
+19406 19406/udp # pfSense nat bouncing
+19407 19407/tcp # pfSense nat bouncing
+19407 19407/udp # pfSense nat bouncing
+19408 19408/tcp # pfSense nat bouncing
+19408 19408/udp # pfSense nat bouncing
+19409 19409/tcp # pfSense nat bouncing
+19409 19409/udp # pfSense nat bouncing
+19410 19410/tcp # pfSense nat bouncing
+19410 19410/udp # pfSense nat bouncing
+19411 19411/tcp # pfSense nat bouncing
+19411 19411/udp # pfSense nat bouncing
+19412 19412/tcp # pfSense nat bouncing
+19412 19412/udp # pfSense nat bouncing
+19413 19413/tcp # pfSense nat bouncing
+19413 19413/udp # pfSense nat bouncing
+19414 19414/tcp # pfSense nat bouncing
+19414 19414/udp # pfSense nat bouncing
+19415 19415/tcp # pfSense nat bouncing
+19415 19415/udp # pfSense nat bouncing
+19416 19416/tcp # pfSense nat bouncing
+19416 19416/udp # pfSense nat bouncing
+19417 19417/tcp # pfSense nat bouncing
+19417 19417/udp # pfSense nat bouncing
+19418 19418/tcp # pfSense nat bouncing
+19418 19418/udp # pfSense nat bouncing
+19419 19419/tcp # pfSense nat bouncing
+19419 19419/udp # pfSense nat bouncing
+19420 19420/tcp # pfSense nat bouncing
+19420 19420/udp # pfSense nat bouncing
+19421 19421/tcp # pfSense nat bouncing
+19421 19421/udp # pfSense nat bouncing
+19422 19422/tcp # pfSense nat bouncing
+19422 19422/udp # pfSense nat bouncing
+19423 19423/tcp # pfSense nat bouncing
+19423 19423/udp # pfSense nat bouncing
+19424 19424/tcp # pfSense nat bouncing
+19424 19424/udp # pfSense nat bouncing
+19425 19425/tcp # pfSense nat bouncing
+19425 19425/udp # pfSense nat bouncing
+19426 19426/tcp # pfSense nat bouncing
+19426 19426/udp # pfSense nat bouncing
+19427 19427/tcp # pfSense nat bouncing
+19427 19427/udp # pfSense nat bouncing
+19428 19428/tcp # pfSense nat bouncing
+19428 19428/udp # pfSense nat bouncing
+19429 19429/tcp # pfSense nat bouncing
+19429 19429/udp # pfSense nat bouncing
+19430 19430/tcp # pfSense nat bouncing
+19430 19430/udp # pfSense nat bouncing
+19431 19431/tcp # pfSense nat bouncing
+19431 19431/udp # pfSense nat bouncing
+19432 19432/tcp # pfSense nat bouncing
+19432 19432/udp # pfSense nat bouncing
+19433 19433/tcp # pfSense nat bouncing
+19433 19433/udp # pfSense nat bouncing
+19434 19434/tcp # pfSense nat bouncing
+19434 19434/udp # pfSense nat bouncing
+19435 19435/tcp # pfSense nat bouncing
+19435 19435/udp # pfSense nat bouncing
+19436 19436/tcp # pfSense nat bouncing
+19436 19436/udp # pfSense nat bouncing
+19437 19437/tcp # pfSense nat bouncing
+19437 19437/udp # pfSense nat bouncing
+19438 19438/tcp # pfSense nat bouncing
+19438 19438/udp # pfSense nat bouncing
+19439 19439/tcp # pfSense nat bouncing
+19439 19439/udp # pfSense nat bouncing
+19440 19440/tcp # pfSense nat bouncing
+19440 19440/udp # pfSense nat bouncing
+19441 19441/tcp # pfSense nat bouncing
+19441 19441/udp # pfSense nat bouncing
+19442 19442/tcp # pfSense nat bouncing
+19442 19442/udp # pfSense nat bouncing
+19443 19443/tcp # pfSense nat bouncing
+19443 19443/udp # pfSense nat bouncing
+19444 19444/tcp # pfSense nat bouncing
+19444 19444/udp # pfSense nat bouncing
+19445 19445/tcp # pfSense nat bouncing
+19445 19445/udp # pfSense nat bouncing
+19446 19446/tcp # pfSense nat bouncing
+19446 19446/udp # pfSense nat bouncing
+19447 19447/tcp # pfSense nat bouncing
+19447 19447/udp # pfSense nat bouncing
+19448 19448/tcp # pfSense nat bouncing
+19448 19448/udp # pfSense nat bouncing
+19449 19449/tcp # pfSense nat bouncing
+19449 19449/udp # pfSense nat bouncing
+19450 19450/tcp # pfSense nat bouncing
+19450 19450/udp # pfSense nat bouncing
+19451 19451/tcp # pfSense nat bouncing
+19451 19451/udp # pfSense nat bouncing
+19452 19452/tcp # pfSense nat bouncing
+19452 19452/udp # pfSense nat bouncing
+19453 19453/tcp # pfSense nat bouncing
+19453 19453/udp # pfSense nat bouncing
+19454 19454/tcp # pfSense nat bouncing
+19454 19454/udp # pfSense nat bouncing
+19455 19455/tcp # pfSense nat bouncing
+19455 19455/udp # pfSense nat bouncing
+19456 19456/tcp # pfSense nat bouncing
+19456 19456/udp # pfSense nat bouncing
+19457 19457/tcp # pfSense nat bouncing
+19457 19457/udp # pfSense nat bouncing
+19458 19458/tcp # pfSense nat bouncing
+19458 19458/udp # pfSense nat bouncing
+19459 19459/tcp # pfSense nat bouncing
+19459 19459/udp # pfSense nat bouncing
+19460 19460/tcp # pfSense nat bouncing
+19460 19460/udp # pfSense nat bouncing
+19461 19461/tcp # pfSense nat bouncing
+19461 19461/udp # pfSense nat bouncing
+19462 19462/tcp # pfSense nat bouncing
+19462 19462/udp # pfSense nat bouncing
+19463 19463/tcp # pfSense nat bouncing
+19463 19463/udp # pfSense nat bouncing
+19464 19464/tcp # pfSense nat bouncing
+19464 19464/udp # pfSense nat bouncing
+19465 19465/tcp # pfSense nat bouncing
+19465 19465/udp # pfSense nat bouncing
+19466 19466/tcp # pfSense nat bouncing
+19466 19466/udp # pfSense nat bouncing
+19467 19467/tcp # pfSense nat bouncing
+19467 19467/udp # pfSense nat bouncing
+19468 19468/tcp # pfSense nat bouncing
+19468 19468/udp # pfSense nat bouncing
+19469 19469/tcp # pfSense nat bouncing
+19469 19469/udp # pfSense nat bouncing
+19470 19470/tcp # pfSense nat bouncing
+19470 19470/udp # pfSense nat bouncing
+19471 19471/tcp # pfSense nat bouncing
+19471 19471/udp # pfSense nat bouncing
+19472 19472/tcp # pfSense nat bouncing
+19472 19472/udp # pfSense nat bouncing
+19473 19473/tcp # pfSense nat bouncing
+19473 19473/udp # pfSense nat bouncing
+19474 19474/tcp # pfSense nat bouncing
+19474 19474/udp # pfSense nat bouncing
+19475 19475/tcp # pfSense nat bouncing
+19475 19475/udp # pfSense nat bouncing
+19476 19476/tcp # pfSense nat bouncing
+19476 19476/udp # pfSense nat bouncing
+19477 19477/tcp # pfSense nat bouncing
+19477 19477/udp # pfSense nat bouncing
+19478 19478/tcp # pfSense nat bouncing
+19478 19478/udp # pfSense nat bouncing
+19479 19479/tcp # pfSense nat bouncing
+19479 19479/udp # pfSense nat bouncing
+19480 19480/tcp # pfSense nat bouncing
+19480 19480/udp # pfSense nat bouncing
+19481 19481/tcp # pfSense nat bouncing
+19481 19481/udp # pfSense nat bouncing
+19482 19482/tcp # pfSense nat bouncing
+19482 19482/udp # pfSense nat bouncing
+19483 19483/tcp # pfSense nat bouncing
+19483 19483/udp # pfSense nat bouncing
+19484 19484/tcp # pfSense nat bouncing
+19484 19484/udp # pfSense nat bouncing
+19485 19485/tcp # pfSense nat bouncing
+19485 19485/udp # pfSense nat bouncing
+19486 19486/tcp # pfSense nat bouncing
+19486 19486/udp # pfSense nat bouncing
+19487 19487/tcp # pfSense nat bouncing
+19487 19487/udp # pfSense nat bouncing
+19488 19488/tcp # pfSense nat bouncing
+19488 19488/udp # pfSense nat bouncing
+19489 19489/tcp # pfSense nat bouncing
+19489 19489/udp # pfSense nat bouncing
+19490 19490/tcp # pfSense nat bouncing
+19490 19490/udp # pfSense nat bouncing
+19491 19491/tcp # pfSense nat bouncing
+19491 19491/udp # pfSense nat bouncing
+19492 19492/tcp # pfSense nat bouncing
+19492 19492/udp # pfSense nat bouncing
+19493 19493/tcp # pfSense nat bouncing
+19493 19493/udp # pfSense nat bouncing
+19494 19494/tcp # pfSense nat bouncing
+19494 19494/udp # pfSense nat bouncing
+19495 19495/tcp # pfSense nat bouncing
+19495 19495/udp # pfSense nat bouncing
+19496 19496/tcp # pfSense nat bouncing
+19496 19496/udp # pfSense nat bouncing
+19497 19497/tcp # pfSense nat bouncing
+19497 19497/udp # pfSense nat bouncing
+19498 19498/tcp # pfSense nat bouncing
+19498 19498/udp # pfSense nat bouncing
+19499 19499/tcp # pfSense nat bouncing
+19499 19499/udp # pfSense nat bouncing
+19500 19500/tcp # pfSense nat bouncing
+19500 19500/udp # pfSense nat bouncing
+19501 19501/tcp # pfSense nat bouncing
+19501 19501/udp # pfSense nat bouncing
+19502 19502/tcp # pfSense nat bouncing
+19502 19502/udp # pfSense nat bouncing
+19503 19503/tcp # pfSense nat bouncing
+19503 19503/udp # pfSense nat bouncing
+19504 19504/tcp # pfSense nat bouncing
+19504 19504/udp # pfSense nat bouncing
+19505 19505/tcp # pfSense nat bouncing
+19505 19505/udp # pfSense nat bouncing
+19506 19506/tcp # pfSense nat bouncing
+19506 19506/udp # pfSense nat bouncing
+19507 19507/tcp # pfSense nat bouncing
+19507 19507/udp # pfSense nat bouncing
+19508 19508/tcp # pfSense nat bouncing
+19508 19508/udp # pfSense nat bouncing
+19509 19509/tcp # pfSense nat bouncing
+19509 19509/udp # pfSense nat bouncing
+19510 19510/tcp # pfSense nat bouncing
+19510 19510/udp # pfSense nat bouncing
+19511 19511/tcp # pfSense nat bouncing
+19511 19511/udp # pfSense nat bouncing
+19512 19512/tcp # pfSense nat bouncing
+19512 19512/udp # pfSense nat bouncing
+19513 19513/tcp # pfSense nat bouncing
+19513 19513/udp # pfSense nat bouncing
+19514 19514/tcp # pfSense nat bouncing
+19514 19514/udp # pfSense nat bouncing
+19515 19515/tcp # pfSense nat bouncing
+19515 19515/udp # pfSense nat bouncing
+19516 19516/tcp # pfSense nat bouncing
+19516 19516/udp # pfSense nat bouncing
+19517 19517/tcp # pfSense nat bouncing
+19517 19517/udp # pfSense nat bouncing
+19518 19518/tcp # pfSense nat bouncing
+19518 19518/udp # pfSense nat bouncing
+19519 19519/tcp # pfSense nat bouncing
+19519 19519/udp # pfSense nat bouncing
+19520 19520/tcp # pfSense nat bouncing
+19520 19520/udp # pfSense nat bouncing
+19521 19521/tcp # pfSense nat bouncing
+19521 19521/udp # pfSense nat bouncing
+19522 19522/tcp # pfSense nat bouncing
+19522 19522/udp # pfSense nat bouncing
+19523 19523/tcp # pfSense nat bouncing
+19523 19523/udp # pfSense nat bouncing
+19524 19524/tcp # pfSense nat bouncing
+19524 19524/udp # pfSense nat bouncing
+19525 19525/tcp # pfSense nat bouncing
+19525 19525/udp # pfSense nat bouncing
+19526 19526/tcp # pfSense nat bouncing
+19526 19526/udp # pfSense nat bouncing
+19527 19527/tcp # pfSense nat bouncing
+19527 19527/udp # pfSense nat bouncing
+19528 19528/tcp # pfSense nat bouncing
+19528 19528/udp # pfSense nat bouncing
+19529 19529/tcp # pfSense nat bouncing
+19529 19529/udp # pfSense nat bouncing
+19530 19530/tcp # pfSense nat bouncing
+19530 19530/udp # pfSense nat bouncing
+19531 19531/tcp # pfSense nat bouncing
+19531 19531/udp # pfSense nat bouncing
+19532 19532/tcp # pfSense nat bouncing
+19532 19532/udp # pfSense nat bouncing
+19533 19533/tcp # pfSense nat bouncing
+19533 19533/udp # pfSense nat bouncing
+19534 19534/tcp # pfSense nat bouncing
+19534 19534/udp # pfSense nat bouncing
+19535 19535/tcp # pfSense nat bouncing
+19535 19535/udp # pfSense nat bouncing
+19536 19536/tcp # pfSense nat bouncing
+19536 19536/udp # pfSense nat bouncing
+19537 19537/tcp # pfSense nat bouncing
+19537 19537/udp # pfSense nat bouncing
+19538 19538/tcp # pfSense nat bouncing
+19538 19538/udp # pfSense nat bouncing
+19539 19539/tcp # pfSense nat bouncing
+19539 19539/udp # pfSense nat bouncing
+19540 19540/tcp # pfSense nat bouncing
+19540 19540/udp # pfSense nat bouncing
+19541 19541/tcp # pfSense nat bouncing
+19541 19541/udp # pfSense nat bouncing
+19542 19542/tcp # pfSense nat bouncing
+19542 19542/udp # pfSense nat bouncing
+19543 19543/tcp # pfSense nat bouncing
+19543 19543/udp # pfSense nat bouncing
+19544 19544/tcp # pfSense nat bouncing
+19544 19544/udp # pfSense nat bouncing
+19545 19545/tcp # pfSense nat bouncing
+19545 19545/udp # pfSense nat bouncing
+19546 19546/tcp # pfSense nat bouncing
+19546 19546/udp # pfSense nat bouncing
+19547 19547/tcp # pfSense nat bouncing
+19547 19547/udp # pfSense nat bouncing
+19548 19548/tcp # pfSense nat bouncing
+19548 19548/udp # pfSense nat bouncing
+19549 19549/tcp # pfSense nat bouncing
+19549 19549/udp # pfSense nat bouncing
+19550 19550/tcp # pfSense nat bouncing
+19550 19550/udp # pfSense nat bouncing
+19551 19551/tcp # pfSense nat bouncing
+19551 19551/udp # pfSense nat bouncing
+19552 19552/tcp # pfSense nat bouncing
+19552 19552/udp # pfSense nat bouncing
+19553 19553/tcp # pfSense nat bouncing
+19553 19553/udp # pfSense nat bouncing
+19554 19554/tcp # pfSense nat bouncing
+19554 19554/udp # pfSense nat bouncing
+19555 19555/tcp # pfSense nat bouncing
+19555 19555/udp # pfSense nat bouncing
+19556 19556/tcp # pfSense nat bouncing
+19556 19556/udp # pfSense nat bouncing
+19557 19557/tcp # pfSense nat bouncing
+19557 19557/udp # pfSense nat bouncing
+19558 19558/tcp # pfSense nat bouncing
+19558 19558/udp # pfSense nat bouncing
+19559 19559/tcp # pfSense nat bouncing
+19559 19559/udp # pfSense nat bouncing
+19560 19560/tcp # pfSense nat bouncing
+19560 19560/udp # pfSense nat bouncing
+19561 19561/tcp # pfSense nat bouncing
+19561 19561/udp # pfSense nat bouncing
+19562 19562/tcp # pfSense nat bouncing
+19562 19562/udp # pfSense nat bouncing
+19563 19563/tcp # pfSense nat bouncing
+19563 19563/udp # pfSense nat bouncing
+19564 19564/tcp # pfSense nat bouncing
+19564 19564/udp # pfSense nat bouncing
+19565 19565/tcp # pfSense nat bouncing
+19565 19565/udp # pfSense nat bouncing
+19566 19566/tcp # pfSense nat bouncing
+19566 19566/udp # pfSense nat bouncing
+19567 19567/tcp # pfSense nat bouncing
+19567 19567/udp # pfSense nat bouncing
+19568 19568/tcp # pfSense nat bouncing
+19568 19568/udp # pfSense nat bouncing
+19569 19569/tcp # pfSense nat bouncing
+19569 19569/udp # pfSense nat bouncing
+19570 19570/tcp # pfSense nat bouncing
+19570 19570/udp # pfSense nat bouncing
+19571 19571/tcp # pfSense nat bouncing
+19571 19571/udp # pfSense nat bouncing
+19572 19572/tcp # pfSense nat bouncing
+19572 19572/udp # pfSense nat bouncing
+19573 19573/tcp # pfSense nat bouncing
+19573 19573/udp # pfSense nat bouncing
+19574 19574/tcp # pfSense nat bouncing
+19574 19574/udp # pfSense nat bouncing
+19575 19575/tcp # pfSense nat bouncing
+19575 19575/udp # pfSense nat bouncing
+19576 19576/tcp # pfSense nat bouncing
+19576 19576/udp # pfSense nat bouncing
+19577 19577/tcp # pfSense nat bouncing
+19577 19577/udp # pfSense nat bouncing
+19578 19578/tcp # pfSense nat bouncing
+19578 19578/udp # pfSense nat bouncing
+19579 19579/tcp # pfSense nat bouncing
+19579 19579/udp # pfSense nat bouncing
+19580 19580/tcp # pfSense nat bouncing
+19580 19580/udp # pfSense nat bouncing
+19581 19581/tcp # pfSense nat bouncing
+19581 19581/udp # pfSense nat bouncing
+19582 19582/tcp # pfSense nat bouncing
+19582 19582/udp # pfSense nat bouncing
+19583 19583/tcp # pfSense nat bouncing
+19583 19583/udp # pfSense nat bouncing
+19584 19584/tcp # pfSense nat bouncing
+19584 19584/udp # pfSense nat bouncing
+19585 19585/tcp # pfSense nat bouncing
+19585 19585/udp # pfSense nat bouncing
+19586 19586/tcp # pfSense nat bouncing
+19586 19586/udp # pfSense nat bouncing
+19587 19587/tcp # pfSense nat bouncing
+19587 19587/udp # pfSense nat bouncing
+19588 19588/tcp # pfSense nat bouncing
+19588 19588/udp # pfSense nat bouncing
+19589 19589/tcp # pfSense nat bouncing
+19589 19589/udp # pfSense nat bouncing
+19590 19590/tcp # pfSense nat bouncing
+19590 19590/udp # pfSense nat bouncing
+19591 19591/tcp # pfSense nat bouncing
+19591 19591/udp # pfSense nat bouncing
+19592 19592/tcp # pfSense nat bouncing
+19592 19592/udp # pfSense nat bouncing
+19593 19593/tcp # pfSense nat bouncing
+19593 19593/udp # pfSense nat bouncing
+19594 19594/tcp # pfSense nat bouncing
+19594 19594/udp # pfSense nat bouncing
+19595 19595/tcp # pfSense nat bouncing
+19595 19595/udp # pfSense nat bouncing
+19596 19596/tcp # pfSense nat bouncing
+19596 19596/udp # pfSense nat bouncing
+19597 19597/tcp # pfSense nat bouncing
+19597 19597/udp # pfSense nat bouncing
+19598 19598/tcp # pfSense nat bouncing
+19598 19598/udp # pfSense nat bouncing
+19599 19599/tcp # pfSense nat bouncing
+19599 19599/udp # pfSense nat bouncing
+19600 19600/tcp # pfSense nat bouncing
+19600 19600/udp # pfSense nat bouncing
+19601 19601/tcp # pfSense nat bouncing
+19601 19601/udp # pfSense nat bouncing
+19602 19602/tcp # pfSense nat bouncing
+19602 19602/udp # pfSense nat bouncing
+19603 19603/tcp # pfSense nat bouncing
+19603 19603/udp # pfSense nat bouncing
+19604 19604/tcp # pfSense nat bouncing
+19604 19604/udp # pfSense nat bouncing
+19605 19605/tcp # pfSense nat bouncing
+19605 19605/udp # pfSense nat bouncing
+19606 19606/tcp # pfSense nat bouncing
+19606 19606/udp # pfSense nat bouncing
+19607 19607/tcp # pfSense nat bouncing
+19607 19607/udp # pfSense nat bouncing
+19608 19608/tcp # pfSense nat bouncing
+19608 19608/udp # pfSense nat bouncing
+19609 19609/tcp # pfSense nat bouncing
+19609 19609/udp # pfSense nat bouncing
+19610 19610/tcp # pfSense nat bouncing
+19610 19610/udp # pfSense nat bouncing
+19611 19611/tcp # pfSense nat bouncing
+19611 19611/udp # pfSense nat bouncing
+19612 19612/tcp # pfSense nat bouncing
+19612 19612/udp # pfSense nat bouncing
+19613 19613/tcp # pfSense nat bouncing
+19613 19613/udp # pfSense nat bouncing
+19614 19614/tcp # pfSense nat bouncing
+19614 19614/udp # pfSense nat bouncing
+19615 19615/tcp # pfSense nat bouncing
+19615 19615/udp # pfSense nat bouncing
+19616 19616/tcp # pfSense nat bouncing
+19616 19616/udp # pfSense nat bouncing
+19617 19617/tcp # pfSense nat bouncing
+19617 19617/udp # pfSense nat bouncing
+19618 19618/tcp # pfSense nat bouncing
+19618 19618/udp # pfSense nat bouncing
+19619 19619/tcp # pfSense nat bouncing
+19619 19619/udp # pfSense nat bouncing
+19620 19620/tcp # pfSense nat bouncing
+19620 19620/udp # pfSense nat bouncing
+19621 19621/tcp # pfSense nat bouncing
+19621 19621/udp # pfSense nat bouncing
+19622 19622/tcp # pfSense nat bouncing
+19622 19622/udp # pfSense nat bouncing
+19623 19623/tcp # pfSense nat bouncing
+19623 19623/udp # pfSense nat bouncing
+19624 19624/tcp # pfSense nat bouncing
+19624 19624/udp # pfSense nat bouncing
+19625 19625/tcp # pfSense nat bouncing
+19625 19625/udp # pfSense nat bouncing
+19626 19626/tcp # pfSense nat bouncing
+19626 19626/udp # pfSense nat bouncing
+19627 19627/tcp # pfSense nat bouncing
+19627 19627/udp # pfSense nat bouncing
+19628 19628/tcp # pfSense nat bouncing
+19628 19628/udp # pfSense nat bouncing
+19629 19629/tcp # pfSense nat bouncing
+19629 19629/udp # pfSense nat bouncing
+19630 19630/tcp # pfSense nat bouncing
+19630 19630/udp # pfSense nat bouncing
+19631 19631/tcp # pfSense nat bouncing
+19631 19631/udp # pfSense nat bouncing
+19632 19632/tcp # pfSense nat bouncing
+19632 19632/udp # pfSense nat bouncing
+19633 19633/tcp # pfSense nat bouncing
+19633 19633/udp # pfSense nat bouncing
+19634 19634/tcp # pfSense nat bouncing
+19634 19634/udp # pfSense nat bouncing
+19635 19635/tcp # pfSense nat bouncing
+19635 19635/udp # pfSense nat bouncing
+19636 19636/tcp # pfSense nat bouncing
+19636 19636/udp # pfSense nat bouncing
+19637 19637/tcp # pfSense nat bouncing
+19637 19637/udp # pfSense nat bouncing
+19638 19638/tcp # pfSense nat bouncing
+19638 19638/udp # pfSense nat bouncing
+19639 19639/tcp # pfSense nat bouncing
+19639 19639/udp # pfSense nat bouncing
+19640 19640/tcp # pfSense nat bouncing
+19640 19640/udp # pfSense nat bouncing
+19641 19641/tcp # pfSense nat bouncing
+19641 19641/udp # pfSense nat bouncing
+19642 19642/tcp # pfSense nat bouncing
+19642 19642/udp # pfSense nat bouncing
+19643 19643/tcp # pfSense nat bouncing
+19643 19643/udp # pfSense nat bouncing
+19644 19644/tcp # pfSense nat bouncing
+19644 19644/udp # pfSense nat bouncing
+19645 19645/tcp # pfSense nat bouncing
+19645 19645/udp # pfSense nat bouncing
+19646 19646/tcp # pfSense nat bouncing
+19646 19646/udp # pfSense nat bouncing
+19647 19647/tcp # pfSense nat bouncing
+19647 19647/udp # pfSense nat bouncing
+19648 19648/tcp # pfSense nat bouncing
+19648 19648/udp # pfSense nat bouncing
+19649 19649/tcp # pfSense nat bouncing
+19649 19649/udp # pfSense nat bouncing
+19650 19650/tcp # pfSense nat bouncing
+19650 19650/udp # pfSense nat bouncing
+19651 19651/tcp # pfSense nat bouncing
+19651 19651/udp # pfSense nat bouncing
+19652 19652/tcp # pfSense nat bouncing
+19652 19652/udp # pfSense nat bouncing
+19653 19653/tcp # pfSense nat bouncing
+19653 19653/udp # pfSense nat bouncing
+19654 19654/tcp # pfSense nat bouncing
+19654 19654/udp # pfSense nat bouncing
+19655 19655/tcp # pfSense nat bouncing
+19655 19655/udp # pfSense nat bouncing
+19656 19656/tcp # pfSense nat bouncing
+19656 19656/udp # pfSense nat bouncing
+19657 19657/tcp # pfSense nat bouncing
+19657 19657/udp # pfSense nat bouncing
+19658 19658/tcp # pfSense nat bouncing
+19658 19658/udp # pfSense nat bouncing
+19659 19659/tcp # pfSense nat bouncing
+19659 19659/udp # pfSense nat bouncing
+19660 19660/tcp # pfSense nat bouncing
+19660 19660/udp # pfSense nat bouncing
+19661 19661/tcp # pfSense nat bouncing
+19661 19661/udp # pfSense nat bouncing
+19662 19662/tcp # pfSense nat bouncing
+19662 19662/udp # pfSense nat bouncing
+19663 19663/tcp # pfSense nat bouncing
+19663 19663/udp # pfSense nat bouncing
+19664 19664/tcp # pfSense nat bouncing
+19664 19664/udp # pfSense nat bouncing
+19665 19665/tcp # pfSense nat bouncing
+19665 19665/udp # pfSense nat bouncing
+19666 19666/tcp # pfSense nat bouncing
+19666 19666/udp # pfSense nat bouncing
+19667 19667/tcp # pfSense nat bouncing
+19667 19667/udp # pfSense nat bouncing
+19668 19668/tcp # pfSense nat bouncing
+19668 19668/udp # pfSense nat bouncing
+19669 19669/tcp # pfSense nat bouncing
+19669 19669/udp # pfSense nat bouncing
+19670 19670/tcp # pfSense nat bouncing
+19670 19670/udp # pfSense nat bouncing
+19671 19671/tcp # pfSense nat bouncing
+19671 19671/udp # pfSense nat bouncing
+19672 19672/tcp # pfSense nat bouncing
+19672 19672/udp # pfSense nat bouncing
+19673 19673/tcp # pfSense nat bouncing
+19673 19673/udp # pfSense nat bouncing
+19674 19674/tcp # pfSense nat bouncing
+19674 19674/udp # pfSense nat bouncing
+19675 19675/tcp # pfSense nat bouncing
+19675 19675/udp # pfSense nat bouncing
+19676 19676/tcp # pfSense nat bouncing
+19676 19676/udp # pfSense nat bouncing
+19677 19677/tcp # pfSense nat bouncing
+19677 19677/udp # pfSense nat bouncing
+19678 19678/tcp # pfSense nat bouncing
+19678 19678/udp # pfSense nat bouncing
+19679 19679/tcp # pfSense nat bouncing
+19679 19679/udp # pfSense nat bouncing
+19680 19680/tcp # pfSense nat bouncing
+19680 19680/udp # pfSense nat bouncing
+19681 19681/tcp # pfSense nat bouncing
+19681 19681/udp # pfSense nat bouncing
+19682 19682/tcp # pfSense nat bouncing
+19682 19682/udp # pfSense nat bouncing
+19683 19683/tcp # pfSense nat bouncing
+19683 19683/udp # pfSense nat bouncing
+19684 19684/tcp # pfSense nat bouncing
+19684 19684/udp # pfSense nat bouncing
+19685 19685/tcp # pfSense nat bouncing
+19685 19685/udp # pfSense nat bouncing
+19686 19686/tcp # pfSense nat bouncing
+19686 19686/udp # pfSense nat bouncing
+19687 19687/tcp # pfSense nat bouncing
+19687 19687/udp # pfSense nat bouncing
+19688 19688/tcp # pfSense nat bouncing
+19688 19688/udp # pfSense nat bouncing
+19689 19689/tcp # pfSense nat bouncing
+19689 19689/udp # pfSense nat bouncing
+19690 19690/tcp # pfSense nat bouncing
+19690 19690/udp # pfSense nat bouncing
+19691 19691/tcp # pfSense nat bouncing
+19691 19691/udp # pfSense nat bouncing
+19692 19692/tcp # pfSense nat bouncing
+19692 19692/udp # pfSense nat bouncing
+19693 19693/tcp # pfSense nat bouncing
+19693 19693/udp # pfSense nat bouncing
+19694 19694/tcp # pfSense nat bouncing
+19694 19694/udp # pfSense nat bouncing
+19695 19695/tcp # pfSense nat bouncing
+19695 19695/udp # pfSense nat bouncing
+19696 19696/tcp # pfSense nat bouncing
+19696 19696/udp # pfSense nat bouncing
+19697 19697/tcp # pfSense nat bouncing
+19697 19697/udp # pfSense nat bouncing
+19698 19698/tcp # pfSense nat bouncing
+19698 19698/udp # pfSense nat bouncing
+19699 19699/tcp # pfSense nat bouncing
+19699 19699/udp # pfSense nat bouncing
+19700 19700/tcp # pfSense nat bouncing
+19700 19700/udp # pfSense nat bouncing
+19701 19701/tcp # pfSense nat bouncing
+19701 19701/udp # pfSense nat bouncing
+19702 19702/tcp # pfSense nat bouncing
+19702 19702/udp # pfSense nat bouncing
+19703 19703/tcp # pfSense nat bouncing
+19703 19703/udp # pfSense nat bouncing
+19704 19704/tcp # pfSense nat bouncing
+19704 19704/udp # pfSense nat bouncing
+19705 19705/tcp # pfSense nat bouncing
+19705 19705/udp # pfSense nat bouncing
+19706 19706/tcp # pfSense nat bouncing
+19706 19706/udp # pfSense nat bouncing
+19707 19707/tcp # pfSense nat bouncing
+19707 19707/udp # pfSense nat bouncing
+19708 19708/tcp # pfSense nat bouncing
+19708 19708/udp # pfSense nat bouncing
+19709 19709/tcp # pfSense nat bouncing
+19709 19709/udp # pfSense nat bouncing
+19710 19710/tcp # pfSense nat bouncing
+19710 19710/udp # pfSense nat bouncing
+19711 19711/tcp # pfSense nat bouncing
+19711 19711/udp # pfSense nat bouncing
+19712 19712/tcp # pfSense nat bouncing
+19712 19712/udp # pfSense nat bouncing
+19713 19713/tcp # pfSense nat bouncing
+19713 19713/udp # pfSense nat bouncing
+19714 19714/tcp # pfSense nat bouncing
+19714 19714/udp # pfSense nat bouncing
+19715 19715/tcp # pfSense nat bouncing
+19715 19715/udp # pfSense nat bouncing
+19716 19716/tcp # pfSense nat bouncing
+19716 19716/udp # pfSense nat bouncing
+19717 19717/tcp # pfSense nat bouncing
+19717 19717/udp # pfSense nat bouncing
+19718 19718/tcp # pfSense nat bouncing
+19718 19718/udp # pfSense nat bouncing
+19719 19719/tcp # pfSense nat bouncing
+19719 19719/udp # pfSense nat bouncing
+19720 19720/tcp # pfSense nat bouncing
+19720 19720/udp # pfSense nat bouncing
+19721 19721/tcp # pfSense nat bouncing
+19721 19721/udp # pfSense nat bouncing
+19722 19722/tcp # pfSense nat bouncing
+19722 19722/udp # pfSense nat bouncing
+19723 19723/tcp # pfSense nat bouncing
+19723 19723/udp # pfSense nat bouncing
+19724 19724/tcp # pfSense nat bouncing
+19724 19724/udp # pfSense nat bouncing
+19725 19725/tcp # pfSense nat bouncing
+19725 19725/udp # pfSense nat bouncing
+19726 19726/tcp # pfSense nat bouncing
+19726 19726/udp # pfSense nat bouncing
+19727 19727/tcp # pfSense nat bouncing
+19727 19727/udp # pfSense nat bouncing
+19728 19728/tcp # pfSense nat bouncing
+19728 19728/udp # pfSense nat bouncing
+19729 19729/tcp # pfSense nat bouncing
+19729 19729/udp # pfSense nat bouncing
+19730 19730/tcp # pfSense nat bouncing
+19730 19730/udp # pfSense nat bouncing
+19731 19731/tcp # pfSense nat bouncing
+19731 19731/udp # pfSense nat bouncing
+19732 19732/tcp # pfSense nat bouncing
+19732 19732/udp # pfSense nat bouncing
+19733 19733/tcp # pfSense nat bouncing
+19733 19733/udp # pfSense nat bouncing
+19734 19734/tcp # pfSense nat bouncing
+19734 19734/udp # pfSense nat bouncing
+19735 19735/tcp # pfSense nat bouncing
+19735 19735/udp # pfSense nat bouncing
+19736 19736/tcp # pfSense nat bouncing
+19736 19736/udp # pfSense nat bouncing
+19737 19737/tcp # pfSense nat bouncing
+19737 19737/udp # pfSense nat bouncing
+19738 19738/tcp # pfSense nat bouncing
+19738 19738/udp # pfSense nat bouncing
+19739 19739/tcp # pfSense nat bouncing
+19739 19739/udp # pfSense nat bouncing
+19740 19740/tcp # pfSense nat bouncing
+19740 19740/udp # pfSense nat bouncing
+19741 19741/tcp # pfSense nat bouncing
+19741 19741/udp # pfSense nat bouncing
+19742 19742/tcp # pfSense nat bouncing
+19742 19742/udp # pfSense nat bouncing
+19743 19743/tcp # pfSense nat bouncing
+19743 19743/udp # pfSense nat bouncing
+19744 19744/tcp # pfSense nat bouncing
+19744 19744/udp # pfSense nat bouncing
+19745 19745/tcp # pfSense nat bouncing
+19745 19745/udp # pfSense nat bouncing
+19746 19746/tcp # pfSense nat bouncing
+19746 19746/udp # pfSense nat bouncing
+19747 19747/tcp # pfSense nat bouncing
+19747 19747/udp # pfSense nat bouncing
+19748 19748/tcp # pfSense nat bouncing
+19748 19748/udp # pfSense nat bouncing
+19749 19749/tcp # pfSense nat bouncing
+19749 19749/udp # pfSense nat bouncing
+19750 19750/tcp # pfSense nat bouncing
+19750 19750/udp # pfSense nat bouncing
+19751 19751/tcp # pfSense nat bouncing
+19751 19751/udp # pfSense nat bouncing
+19752 19752/tcp # pfSense nat bouncing
+19752 19752/udp # pfSense nat bouncing
+19753 19753/tcp # pfSense nat bouncing
+19753 19753/udp # pfSense nat bouncing
+19754 19754/tcp # pfSense nat bouncing
+19754 19754/udp # pfSense nat bouncing
+19755 19755/tcp # pfSense nat bouncing
+19755 19755/udp # pfSense nat bouncing
+19756 19756/tcp # pfSense nat bouncing
+19756 19756/udp # pfSense nat bouncing
+19757 19757/tcp # pfSense nat bouncing
+19757 19757/udp # pfSense nat bouncing
+19758 19758/tcp # pfSense nat bouncing
+19758 19758/udp # pfSense nat bouncing
+19759 19759/tcp # pfSense nat bouncing
+19759 19759/udp # pfSense nat bouncing
+19760 19760/tcp # pfSense nat bouncing
+19760 19760/udp # pfSense nat bouncing
+19761 19761/tcp # pfSense nat bouncing
+19761 19761/udp # pfSense nat bouncing
+19762 19762/tcp # pfSense nat bouncing
+19762 19762/udp # pfSense nat bouncing
+19763 19763/tcp # pfSense nat bouncing
+19763 19763/udp # pfSense nat bouncing
+19764 19764/tcp # pfSense nat bouncing
+19764 19764/udp # pfSense nat bouncing
+19765 19765/tcp # pfSense nat bouncing
+19765 19765/udp # pfSense nat bouncing
+19766 19766/tcp # pfSense nat bouncing
+19766 19766/udp # pfSense nat bouncing
+19767 19767/tcp # pfSense nat bouncing
+19767 19767/udp # pfSense nat bouncing
+19768 19768/tcp # pfSense nat bouncing
+19768 19768/udp # pfSense nat bouncing
+19769 19769/tcp # pfSense nat bouncing
+19769 19769/udp # pfSense nat bouncing
+19770 19770/tcp # pfSense nat bouncing
+19770 19770/udp # pfSense nat bouncing
+19771 19771/tcp # pfSense nat bouncing
+19771 19771/udp # pfSense nat bouncing
+19772 19772/tcp # pfSense nat bouncing
+19772 19772/udp # pfSense nat bouncing
+19773 19773/tcp # pfSense nat bouncing
+19773 19773/udp # pfSense nat bouncing
+19774 19774/tcp # pfSense nat bouncing
+19774 19774/udp # pfSense nat bouncing
+19775 19775/tcp # pfSense nat bouncing
+19775 19775/udp # pfSense nat bouncing
+19776 19776/tcp # pfSense nat bouncing
+19776 19776/udp # pfSense nat bouncing
+19777 19777/tcp # pfSense nat bouncing
+19777 19777/udp # pfSense nat bouncing
+19778 19778/tcp # pfSense nat bouncing
+19778 19778/udp # pfSense nat bouncing
+19779 19779/tcp # pfSense nat bouncing
+19779 19779/udp # pfSense nat bouncing
+19780 19780/tcp # pfSense nat bouncing
+19780 19780/udp # pfSense nat bouncing
+19781 19781/tcp # pfSense nat bouncing
+19781 19781/udp # pfSense nat bouncing
+19782 19782/tcp # pfSense nat bouncing
+19782 19782/udp # pfSense nat bouncing
+19783 19783/tcp # pfSense nat bouncing
+19783 19783/udp # pfSense nat bouncing
+19784 19784/tcp # pfSense nat bouncing
+19784 19784/udp # pfSense nat bouncing
+19785 19785/tcp # pfSense nat bouncing
+19785 19785/udp # pfSense nat bouncing
+19786 19786/tcp # pfSense nat bouncing
+19786 19786/udp # pfSense nat bouncing
+19787 19787/tcp # pfSense nat bouncing
+19787 19787/udp # pfSense nat bouncing
+19788 19788/tcp # pfSense nat bouncing
+19788 19788/udp # pfSense nat bouncing
+19789 19789/tcp # pfSense nat bouncing
+19789 19789/udp # pfSense nat bouncing
+19790 19790/tcp # pfSense nat bouncing
+19790 19790/udp # pfSense nat bouncing
+19791 19791/tcp # pfSense nat bouncing
+19791 19791/udp # pfSense nat bouncing
+19792 19792/tcp # pfSense nat bouncing
+19792 19792/udp # pfSense nat bouncing
+19793 19793/tcp # pfSense nat bouncing
+19793 19793/udp # pfSense nat bouncing
+19794 19794/tcp # pfSense nat bouncing
+19794 19794/udp # pfSense nat bouncing
+19795 19795/tcp # pfSense nat bouncing
+19795 19795/udp # pfSense nat bouncing
+19796 19796/tcp # pfSense nat bouncing
+19796 19796/udp # pfSense nat bouncing
+19797 19797/tcp # pfSense nat bouncing
+19797 19797/udp # pfSense nat bouncing
+19798 19798/tcp # pfSense nat bouncing
+19798 19798/udp # pfSense nat bouncing
+19799 19799/tcp # pfSense nat bouncing
+19799 19799/udp # pfSense nat bouncing
+19800 19800/tcp # pfSense nat bouncing
+19800 19800/udp # pfSense nat bouncing
+19801 19801/tcp # pfSense nat bouncing
+19801 19801/udp # pfSense nat bouncing
+19802 19802/tcp # pfSense nat bouncing
+19802 19802/udp # pfSense nat bouncing
+19803 19803/tcp # pfSense nat bouncing
+19803 19803/udp # pfSense nat bouncing
+19804 19804/tcp # pfSense nat bouncing
+19804 19804/udp # pfSense nat bouncing
+19805 19805/tcp # pfSense nat bouncing
+19805 19805/udp # pfSense nat bouncing
+19806 19806/tcp # pfSense nat bouncing
+19806 19806/udp # pfSense nat bouncing
+19807 19807/tcp # pfSense nat bouncing
+19807 19807/udp # pfSense nat bouncing
+19808 19808/tcp # pfSense nat bouncing
+19808 19808/udp # pfSense nat bouncing
+19809 19809/tcp # pfSense nat bouncing
+19809 19809/udp # pfSense nat bouncing
+19810 19810/tcp # pfSense nat bouncing
+19810 19810/udp # pfSense nat bouncing
+19811 19811/tcp # pfSense nat bouncing
+19811 19811/udp # pfSense nat bouncing
+19812 19812/tcp # pfSense nat bouncing
+19812 19812/udp # pfSense nat bouncing
+19813 19813/tcp # pfSense nat bouncing
+19813 19813/udp # pfSense nat bouncing
+19814 19814/tcp # pfSense nat bouncing
+19814 19814/udp # pfSense nat bouncing
+19815 19815/tcp # pfSense nat bouncing
+19815 19815/udp # pfSense nat bouncing
+19816 19816/tcp # pfSense nat bouncing
+19816 19816/udp # pfSense nat bouncing
+19817 19817/tcp # pfSense nat bouncing
+19817 19817/udp # pfSense nat bouncing
+19818 19818/tcp # pfSense nat bouncing
+19818 19818/udp # pfSense nat bouncing
+19819 19819/tcp # pfSense nat bouncing
+19819 19819/udp # pfSense nat bouncing
+19820 19820/tcp # pfSense nat bouncing
+19820 19820/udp # pfSense nat bouncing
+19821 19821/tcp # pfSense nat bouncing
+19821 19821/udp # pfSense nat bouncing
+19822 19822/tcp # pfSense nat bouncing
+19822 19822/udp # pfSense nat bouncing
+19823 19823/tcp # pfSense nat bouncing
+19823 19823/udp # pfSense nat bouncing
+19824 19824/tcp # pfSense nat bouncing
+19824 19824/udp # pfSense nat bouncing
+19825 19825/tcp # pfSense nat bouncing
+19825 19825/udp # pfSense nat bouncing
+19826 19826/tcp # pfSense nat bouncing
+19826 19826/udp # pfSense nat bouncing
+19827 19827/tcp # pfSense nat bouncing
+19827 19827/udp # pfSense nat bouncing
+19828 19828/tcp # pfSense nat bouncing
+19828 19828/udp # pfSense nat bouncing
+19829 19829/tcp # pfSense nat bouncing
+19829 19829/udp # pfSense nat bouncing
+19830 19830/tcp # pfSense nat bouncing
+19830 19830/udp # pfSense nat bouncing
+19831 19831/tcp # pfSense nat bouncing
+19831 19831/udp # pfSense nat bouncing
+19832 19832/tcp # pfSense nat bouncing
+19832 19832/udp # pfSense nat bouncing
+19833 19833/tcp # pfSense nat bouncing
+19833 19833/udp # pfSense nat bouncing
+19834 19834/tcp # pfSense nat bouncing
+19834 19834/udp # pfSense nat bouncing
+19835 19835/tcp # pfSense nat bouncing
+19835 19835/udp # pfSense nat bouncing
+19836 19836/tcp # pfSense nat bouncing
+19836 19836/udp # pfSense nat bouncing
+19837 19837/tcp # pfSense nat bouncing
+19837 19837/udp # pfSense nat bouncing
+19838 19838/tcp # pfSense nat bouncing
+19838 19838/udp # pfSense nat bouncing
+19839 19839/tcp # pfSense nat bouncing
+19839 19839/udp # pfSense nat bouncing
+19840 19840/tcp # pfSense nat bouncing
+19840 19840/udp # pfSense nat bouncing
+19841 19841/tcp # pfSense nat bouncing
+19841 19841/udp # pfSense nat bouncing
+19842 19842/tcp # pfSense nat bouncing
+19842 19842/udp # pfSense nat bouncing
+19843 19843/tcp # pfSense nat bouncing
+19843 19843/udp # pfSense nat bouncing
+19844 19844/tcp # pfSense nat bouncing
+19844 19844/udp # pfSense nat bouncing
+19845 19845/tcp # pfSense nat bouncing
+19845 19845/udp # pfSense nat bouncing
+19846 19846/tcp # pfSense nat bouncing
+19846 19846/udp # pfSense nat bouncing
+19847 19847/tcp # pfSense nat bouncing
+19847 19847/udp # pfSense nat bouncing
+19848 19848/tcp # pfSense nat bouncing
+19848 19848/udp # pfSense nat bouncing
+19849 19849/tcp # pfSense nat bouncing
+19849 19849/udp # pfSense nat bouncing
+19850 19850/tcp # pfSense nat bouncing
+19850 19850/udp # pfSense nat bouncing
+19851 19851/tcp # pfSense nat bouncing
+19851 19851/udp # pfSense nat bouncing
+19852 19852/tcp # pfSense nat bouncing
+19852 19852/udp # pfSense nat bouncing
+19853 19853/tcp # pfSense nat bouncing
+19853 19853/udp # pfSense nat bouncing
+19854 19854/tcp # pfSense nat bouncing
+19854 19854/udp # pfSense nat bouncing
+19855 19855/tcp # pfSense nat bouncing
+19855 19855/udp # pfSense nat bouncing
+19856 19856/tcp # pfSense nat bouncing
+19856 19856/udp # pfSense nat bouncing
+19857 19857/tcp # pfSense nat bouncing
+19857 19857/udp # pfSense nat bouncing
+19858 19858/tcp # pfSense nat bouncing
+19858 19858/udp # pfSense nat bouncing
+19859 19859/tcp # pfSense nat bouncing
+19859 19859/udp # pfSense nat bouncing
+19860 19860/tcp # pfSense nat bouncing
+19860 19860/udp # pfSense nat bouncing
+19861 19861/tcp # pfSense nat bouncing
+19861 19861/udp # pfSense nat bouncing
+19862 19862/tcp # pfSense nat bouncing
+19862 19862/udp # pfSense nat bouncing
+19863 19863/tcp # pfSense nat bouncing
+19863 19863/udp # pfSense nat bouncing
+19864 19864/tcp # pfSense nat bouncing
+19864 19864/udp # pfSense nat bouncing
+19865 19865/tcp # pfSense nat bouncing
+19865 19865/udp # pfSense nat bouncing
+19866 19866/tcp # pfSense nat bouncing
+19866 19866/udp # pfSense nat bouncing
+19867 19867/tcp # pfSense nat bouncing
+19867 19867/udp # pfSense nat bouncing
+19868 19868/tcp # pfSense nat bouncing
+19868 19868/udp # pfSense nat bouncing
+19869 19869/tcp # pfSense nat bouncing
+19869 19869/udp # pfSense nat bouncing
+19870 19870/tcp # pfSense nat bouncing
+19870 19870/udp # pfSense nat bouncing
+19871 19871/tcp # pfSense nat bouncing
+19871 19871/udp # pfSense nat bouncing
+19872 19872/tcp # pfSense nat bouncing
+19872 19872/udp # pfSense nat bouncing
+19873 19873/tcp # pfSense nat bouncing
+19873 19873/udp # pfSense nat bouncing
+19874 19874/tcp # pfSense nat bouncing
+19874 19874/udp # pfSense nat bouncing
+19875 19875/tcp # pfSense nat bouncing
+19875 19875/udp # pfSense nat bouncing
+19876 19876/tcp # pfSense nat bouncing
+19876 19876/udp # pfSense nat bouncing
+19877 19877/tcp # pfSense nat bouncing
+19877 19877/udp # pfSense nat bouncing
+19878 19878/tcp # pfSense nat bouncing
+19878 19878/udp # pfSense nat bouncing
+19879 19879/tcp # pfSense nat bouncing
+19879 19879/udp # pfSense nat bouncing
+19880 19880/tcp # pfSense nat bouncing
+19880 19880/udp # pfSense nat bouncing
+19881 19881/tcp # pfSense nat bouncing
+19881 19881/udp # pfSense nat bouncing
+19882 19882/tcp # pfSense nat bouncing
+19882 19882/udp # pfSense nat bouncing
+19883 19883/tcp # pfSense nat bouncing
+19883 19883/udp # pfSense nat bouncing
+19884 19884/tcp # pfSense nat bouncing
+19884 19884/udp # pfSense nat bouncing
+19885 19885/tcp # pfSense nat bouncing
+19885 19885/udp # pfSense nat bouncing
+19886 19886/tcp # pfSense nat bouncing
+19886 19886/udp # pfSense nat bouncing
+19887 19887/tcp # pfSense nat bouncing
+19887 19887/udp # pfSense nat bouncing
+19888 19888/tcp # pfSense nat bouncing
+19888 19888/udp # pfSense nat bouncing
+19889 19889/tcp # pfSense nat bouncing
+19889 19889/udp # pfSense nat bouncing
+19890 19890/tcp # pfSense nat bouncing
+19890 19890/udp # pfSense nat bouncing
+19891 19891/tcp # pfSense nat bouncing
+19891 19891/udp # pfSense nat bouncing
+19892 19892/tcp # pfSense nat bouncing
+19892 19892/udp # pfSense nat bouncing
+19893 19893/tcp # pfSense nat bouncing
+19893 19893/udp # pfSense nat bouncing
+19894 19894/tcp # pfSense nat bouncing
+19894 19894/udp # pfSense nat bouncing
+19895 19895/tcp # pfSense nat bouncing
+19895 19895/udp # pfSense nat bouncing
+19896 19896/tcp # pfSense nat bouncing
+19896 19896/udp # pfSense nat bouncing
+19897 19897/tcp # pfSense nat bouncing
+19897 19897/udp # pfSense nat bouncing
+19898 19898/tcp # pfSense nat bouncing
+19898 19898/udp # pfSense nat bouncing
+19899 19899/tcp # pfSense nat bouncing
+19899 19899/udp # pfSense nat bouncing
+19900 19900/tcp # pfSense nat bouncing
+19900 19900/udp # pfSense nat bouncing
+19901 19901/tcp # pfSense nat bouncing
+19901 19901/udp # pfSense nat bouncing
+19902 19902/tcp # pfSense nat bouncing
+19902 19902/udp # pfSense nat bouncing
+19903 19903/tcp # pfSense nat bouncing
+19903 19903/udp # pfSense nat bouncing
+19904 19904/tcp # pfSense nat bouncing
+19904 19904/udp # pfSense nat bouncing
+19905 19905/tcp # pfSense nat bouncing
+19905 19905/udp # pfSense nat bouncing
+19906 19906/tcp # pfSense nat bouncing
+19906 19906/udp # pfSense nat bouncing
+19907 19907/tcp # pfSense nat bouncing
+19907 19907/udp # pfSense nat bouncing
+19908 19908/tcp # pfSense nat bouncing
+19908 19908/udp # pfSense nat bouncing
+19909 19909/tcp # pfSense nat bouncing
+19909 19909/udp # pfSense nat bouncing
+19910 19910/tcp # pfSense nat bouncing
+19910 19910/udp # pfSense nat bouncing
+19911 19911/tcp # pfSense nat bouncing
+19911 19911/udp # pfSense nat bouncing
+19912 19912/tcp # pfSense nat bouncing
+19912 19912/udp # pfSense nat bouncing
+19913 19913/tcp # pfSense nat bouncing
+19913 19913/udp # pfSense nat bouncing
+19914 19914/tcp # pfSense nat bouncing
+19914 19914/udp # pfSense nat bouncing
+19915 19915/tcp # pfSense nat bouncing
+19915 19915/udp # pfSense nat bouncing
+19916 19916/tcp # pfSense nat bouncing
+19916 19916/udp # pfSense nat bouncing
+19917 19917/tcp # pfSense nat bouncing
+19917 19917/udp # pfSense nat bouncing
+19918 19918/tcp # pfSense nat bouncing
+19918 19918/udp # pfSense nat bouncing
+19919 19919/tcp # pfSense nat bouncing
+19919 19919/udp # pfSense nat bouncing
+19920 19920/tcp # pfSense nat bouncing
+19920 19920/udp # pfSense nat bouncing
+19921 19921/tcp # pfSense nat bouncing
+19921 19921/udp # pfSense nat bouncing
+19922 19922/tcp # pfSense nat bouncing
+19922 19922/udp # pfSense nat bouncing
+19923 19923/tcp # pfSense nat bouncing
+19923 19923/udp # pfSense nat bouncing
+19924 19924/tcp # pfSense nat bouncing
+19924 19924/udp # pfSense nat bouncing
+19925 19925/tcp # pfSense nat bouncing
+19925 19925/udp # pfSense nat bouncing
+19926 19926/tcp # pfSense nat bouncing
+19926 19926/udp # pfSense nat bouncing
+19927 19927/tcp # pfSense nat bouncing
+19927 19927/udp # pfSense nat bouncing
+19928 19928/tcp # pfSense nat bouncing
+19928 19928/udp # pfSense nat bouncing
+19929 19929/tcp # pfSense nat bouncing
+19929 19929/udp # pfSense nat bouncing
+19930 19930/tcp # pfSense nat bouncing
+19930 19930/udp # pfSense nat bouncing
+19931 19931/tcp # pfSense nat bouncing
+19931 19931/udp # pfSense nat bouncing
+19932 19932/tcp # pfSense nat bouncing
+19932 19932/udp # pfSense nat bouncing
+19933 19933/tcp # pfSense nat bouncing
+19933 19933/udp # pfSense nat bouncing
+19934 19934/tcp # pfSense nat bouncing
+19934 19934/udp # pfSense nat bouncing
+19935 19935/tcp # pfSense nat bouncing
+19935 19935/udp # pfSense nat bouncing
+19936 19936/tcp # pfSense nat bouncing
+19936 19936/udp # pfSense nat bouncing
+19937 19937/tcp # pfSense nat bouncing
+19937 19937/udp # pfSense nat bouncing
+19938 19938/tcp # pfSense nat bouncing
+19938 19938/udp # pfSense nat bouncing
+19939 19939/tcp # pfSense nat bouncing
+19939 19939/udp # pfSense nat bouncing
+19940 19940/tcp # pfSense nat bouncing
+19940 19940/udp # pfSense nat bouncing
+19941 19941/tcp # pfSense nat bouncing
+19941 19941/udp # pfSense nat bouncing
+19942 19942/tcp # pfSense nat bouncing
+19942 19942/udp # pfSense nat bouncing
+19943 19943/tcp # pfSense nat bouncing
+19943 19943/udp # pfSense nat bouncing
+19944 19944/tcp # pfSense nat bouncing
+19944 19944/udp # pfSense nat bouncing
+19945 19945/tcp # pfSense nat bouncing
+19945 19945/udp # pfSense nat bouncing
+19946 19946/tcp # pfSense nat bouncing
+19946 19946/udp # pfSense nat bouncing
+19947 19947/tcp # pfSense nat bouncing
+19947 19947/udp # pfSense nat bouncing
+19948 19948/tcp # pfSense nat bouncing
+19948 19948/udp # pfSense nat bouncing
+19949 19949/tcp # pfSense nat bouncing
+19949 19949/udp # pfSense nat bouncing
+19950 19950/tcp # pfSense nat bouncing
+19950 19950/udp # pfSense nat bouncing
+19951 19951/tcp # pfSense nat bouncing
+19951 19951/udp # pfSense nat bouncing
+19952 19952/tcp # pfSense nat bouncing
+19952 19952/udp # pfSense nat bouncing
+19953 19953/tcp # pfSense nat bouncing
+19953 19953/udp # pfSense nat bouncing
+19954 19954/tcp # pfSense nat bouncing
+19954 19954/udp # pfSense nat bouncing
+19955 19955/tcp # pfSense nat bouncing
+19955 19955/udp # pfSense nat bouncing
+19956 19956/tcp # pfSense nat bouncing
+19956 19956/udp # pfSense nat bouncing
+19957 19957/tcp # pfSense nat bouncing
+19957 19957/udp # pfSense nat bouncing
+19958 19958/tcp # pfSense nat bouncing
+19958 19958/udp # pfSense nat bouncing
+19959 19959/tcp # pfSense nat bouncing
+19959 19959/udp # pfSense nat bouncing
+19960 19960/tcp # pfSense nat bouncing
+19960 19960/udp # pfSense nat bouncing
+19961 19961/tcp # pfSense nat bouncing
+19961 19961/udp # pfSense nat bouncing
+19962 19962/tcp # pfSense nat bouncing
+19962 19962/udp # pfSense nat bouncing
+19963 19963/tcp # pfSense nat bouncing
+19963 19963/udp # pfSense nat bouncing
+19964 19964/tcp # pfSense nat bouncing
+19964 19964/udp # pfSense nat bouncing
+19965 19965/tcp # pfSense nat bouncing
+19965 19965/udp # pfSense nat bouncing
+19966 19966/tcp # pfSense nat bouncing
+19966 19966/udp # pfSense nat bouncing
+19967 19967/tcp # pfSense nat bouncing
+19967 19967/udp # pfSense nat bouncing
+19968 19968/tcp # pfSense nat bouncing
+19968 19968/udp # pfSense nat bouncing
+19969 19969/tcp # pfSense nat bouncing
+19969 19969/udp # pfSense nat bouncing
+19970 19970/tcp # pfSense nat bouncing
+19970 19970/udp # pfSense nat bouncing
+19971 19971/tcp # pfSense nat bouncing
+19971 19971/udp # pfSense nat bouncing
+19972 19972/tcp # pfSense nat bouncing
+19972 19972/udp # pfSense nat bouncing
+19973 19973/tcp # pfSense nat bouncing
+19973 19973/udp # pfSense nat bouncing
+19974 19974/tcp # pfSense nat bouncing
+19974 19974/udp # pfSense nat bouncing
+19975 19975/tcp # pfSense nat bouncing
+19975 19975/udp # pfSense nat bouncing
+19976 19976/tcp # pfSense nat bouncing
+19976 19976/udp # pfSense nat bouncing
+19977 19977/tcp # pfSense nat bouncing
+19977 19977/udp # pfSense nat bouncing
+19978 19978/tcp # pfSense nat bouncing
+19978 19978/udp # pfSense nat bouncing
+19979 19979/tcp # pfSense nat bouncing
+19979 19979/udp # pfSense nat bouncing
+19980 19980/tcp # pfSense nat bouncing
+19980 19980/udp # pfSense nat bouncing
+19981 19981/tcp # pfSense nat bouncing
+19981 19981/udp # pfSense nat bouncing
+19982 19982/tcp # pfSense nat bouncing
+19982 19982/udp # pfSense nat bouncing
+19983 19983/tcp # pfSense nat bouncing
+19983 19983/udp # pfSense nat bouncing
+19984 19984/tcp # pfSense nat bouncing
+19984 19984/udp # pfSense nat bouncing
+19985 19985/tcp # pfSense nat bouncing
+19985 19985/udp # pfSense nat bouncing
+19986 19986/tcp # pfSense nat bouncing
+19986 19986/udp # pfSense nat bouncing
+19987 19987/tcp # pfSense nat bouncing
+19987 19987/udp # pfSense nat bouncing
+19988 19988/tcp # pfSense nat bouncing
+19988 19988/udp # pfSense nat bouncing
+19989 19989/tcp # pfSense nat bouncing
+19989 19989/udp # pfSense nat bouncing
+19990 19990/tcp # pfSense nat bouncing
+19990 19990/udp # pfSense nat bouncing
+19991 19991/tcp # pfSense nat bouncing
+19991 19991/udp # pfSense nat bouncing
+19992 19992/tcp # pfSense nat bouncing
+19992 19992/udp # pfSense nat bouncing
+19993 19993/tcp # pfSense nat bouncing
+19993 19993/udp # pfSense nat bouncing
+19994 19994/tcp # pfSense nat bouncing
+19994 19994/udp # pfSense nat bouncing
+19995 19995/tcp # pfSense nat bouncing
+19995 19995/udp # pfSense nat bouncing
+19996 19996/tcp # pfSense nat bouncing
+19996 19996/udp # pfSense nat bouncing
+19997 19997/tcp # pfSense nat bouncing
+19997 19997/udp # pfSense nat bouncing
+19998 19998/tcp # pfSense nat bouncing
+19998 19998/udp # pfSense nat bouncing
+19999 19999/tcp # pfSense nat bouncing
+19999 19999/udp # pfSense nat bouncing
+dbbrowse 47557/tcp #Databeam Corporation
+dbbrowse 47557/udp #Databeam Corporation
+wnn4 22273/tcp #Wnn4 (Japanese input)
+wnn4_Cn 22289/tcp #Wnn4 (Chinese input)
+wnn4_Tw 22321/tcp #Wnn4 (Taiwanse input)
+wnn4_Kr 22305/tcp #Wnn4 (Korean input)
+wnn6 22273/tcp #Wnn6 (Japanese input)
+wnn6_Cn 22289/tcp #Wnn6 (Chinese input)
+wnn6_Tw 22321/tcp #Wnn6 (Taiwanse input)
+wnn6_Kr 22305/tcp #Wnn6 (Korean input)
+wnn6_DS 26208/tcp #Wnn6 (Dserver)
diff --git a/src/etc/shells b/src/etc/shells
new file mode 100644
index 0000000..3ccb4dc
--- /dev/null
+++ b/src/etc/shells
@@ -0,0 +1,12 @@
+# $FreeBSD: src/etc/shells,v 1.5 2000/04/27 21:58:46 ache Exp $
+#
+# List of acceptable shells for chpass(1).
+# Ftpd will not allow users to connect who are not using
+# one of these shells.
+
+/bin/sh
+/bin/csh
+/bin/tcsh
+/etc/rc.initial
+/usr/local/sbin/ssh_tunnel_shell
+
diff --git a/src/etc/skel/dot.profile b/src/etc/skel/dot.profile
new file mode 100644
index 0000000..700597a
--- /dev/null
+++ b/src/etc/skel/dot.profile
@@ -0,0 +1,5 @@
+# Detect interactive logins and display the shell
+if [ -n "${SSH_TTY}" -o "${TERM}" = "cons25" ]; then
+ /etc/rc.initial
+ exit
+fi
diff --git a/src/etc/skel/dot.shrc b/src/etc/skel/dot.shrc
new file mode 100644
index 0000000..6f3c2fc
--- /dev/null
+++ b/src/etc/skel/dot.shrc
@@ -0,0 +1,14 @@
+HTTP_PROXY=`/usr/local/bin/xmllint --xpath 'string(//pfsense/system/proxyurl)' /conf/config.xml`
+if [ "${HTTP_PROXY}" != "" ]; then
+ HTTP_PROXY_PORT=`/usr/local/bin/xmllint --xpath 'string(//pfsense/system/proxyport)' /conf/config.xml`
+ if [ "${HTTP_PROXY_PORT}" != "" ]; then
+ HTTP_PROXY="${HTTP_PROXY}:${HTTP_PROXY_PORT}"
+ fi
+ export HTTP_PROXY
+fi
+
+# Detect interactive logins and display the shell
+if [ -n "${SSH_TTY}" -o "${TERM}" = "cons25" ]; then
+ /etc/rc.initial
+ exit
+fi
diff --git a/src/etc/skel/dot.tcshrc b/src/etc/skel/dot.tcshrc
new file mode 100644
index 0000000..38cf897
--- /dev/null
+++ b/src/etc/skel/dot.tcshrc
@@ -0,0 +1,30 @@
+set prompt="%{\033[0;1;33m%}[%{\033[0;1;37m%}`cat /etc/version`%{\033[0;1;33m%}]%{\033[0;1;33m%}%B[%{\033[0;1;37m%}%n%{\033[0;1;31m%}@%{\033[0;1;37m%}%M%{\033[0;1;33m%}]%{\033[0;1;32m%}%b%/%{\033[0;1;33m%}%{\033[0;1;36m%}%{\033[0;1;31m%}:%{\033[0;0;0m%} "
+set autologout="0"
+set autolist set color set colorcat
+setenv CLICOLOR "true"
+setenv LSCOLORS "exfxcxdxbxegedabagacad"
+if ($term == "xterm" || $term == "vt100" || $term == "vt102" || $term == "vt220" || $term !~ "con*") then
+ bindkey "\e[2~" overwrite-mode # Ins
+ bindkey "\e[3~" delete-char # Del
+
+ bindkey "\e[1~" beginning-of-line # Home vt
+ bindkey "\e[4~" end-of-line # End vt
+
+ bindkey "\eOH" beginning-of-line # Home vt220
+ bindkey "\eOF" end-of-line # End vt220
+
+ bindkey "\e[H" beginning-of-line # Home kvt
+ bindkey "\e[F" end-of-line # End kvt
+
+ bindkey "\e[7~" beginning-of-line # Home rxvt/konsole
+ bindkey "\e[8~" end-of-line # End rxvt/konsole
+endif
+
+set http_proxy=`/usr/local/bin/xmllint --xpath 'string(//pfsense/system/proxyurl)' /conf/config.xml`
+if (${http_proxy} != "") then
+ set http_proxy_port=`/usr/local/bin/xmllint --xpath 'string(//pfsense/system/proxyport)' /conf/config.xml`
+ if (${http_proxy_port} != "") then
+ set http_proxy="${http_proxy}:${http_proxy_port}"
+ endif
+ setenv HTTP_PROXY ${http_proxy}
+endif
diff --git a/src/etc/ssh/sshd_config b/src/etc/ssh/sshd_config
new file mode 100644
index 0000000..f2f288b
--- /dev/null
+++ b/src/etc/ssh/sshd_config
@@ -0,0 +1,103 @@
+# $OpenBSD: sshd_config,v 1.68 2003/12/29 16:39:50 millert Exp $
+# $FreeBSD: src/crypto/openssh/sshd_config,v 1.40 2004/04/20 09:37:29 des Exp $
+
+# This is the sshd server system-wide configuration file. See
+# sshd_config(5) for more information.
+
+# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
+
+# The strategy used for options in the default sshd_config shipped with
+# OpenSSH is to specify options with their default value where
+# possible, but leave them commented. Uncommented options change a
+# default value.
+
+# Note that some of FreeBSD's defaults differ from OpenBSD's, and
+# FreeBSD has a few additional options.
+
+#VersionAddendum FreeBSD-20040419
+
+#Port 22
+#Protocol 2
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 1h
+#ServerKeyBits 768
+
+# Logging
+#obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+#LogLevel INFO
+
+# Authentication:
+
+#LoginGraceTime 2m
+PermitRootLogin yes
+#StrictModes yes
+
+#RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile .ssh/authorized_keys
+
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
+# similar for protocol version 2
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+
+# Change to yes to enable built-in password authentication.
+#PasswordAuthentication no
+#PermitEmptyPasswords no
+
+# Change to no to disable PAM authentication
+#ChallengeResponseAuthentication yes
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+#KerberosGetAFSToken no
+
+# GSSAPI options
+#GSSAPIAuthentication no
+#GSSAPICleanupCredentials yes
+
+# Set this to 'no' to disable PAM authentication (via challenge-response)
+# and session processing.
+#UsePAM yes
+
+#AllowTcpForwarding yes
+#GatewayPorts no
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#TCPKeepAlive yes
+#UseLogin no
+#UsePrivilegeSeparation yes
+#PermitUserEnvironment no
+
+#PidFile /var/run/sshd.pid
+#MaxStartups 10
+
+# no default banner path
+#Banner /some/path
+
+Compression yes
+ClientAliveInterval 30
+ClientAliveCountMax 5
+UseDNS no
+X11Forwarding no
+
+# override default of no subsystems
+Subsystem sftp /usr/libexec/sftp-server
diff --git a/src/etc/sshd b/src/etc/sshd
new file mode 100755
index 0000000..05ddb63
--- /dev/null
+++ b/src/etc/sshd
@@ -0,0 +1,207 @@
+#!/usr/local/bin/php-cgi -f
+<?php
+/*
+ sshd - Modified to work on disk based system
+ Copyright 2004 Scott K Ullrich
+
+ Original Copyright (C) 2004 Fred Mol <fredmol@xs4all.nl>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+ require_once("globals.inc");
+ require_once("config.inc");
+ require_once("functions.inc");
+ require_once("shaper.inc");
+
+ if (!isset($config['system']['enablesshd'])) {
+ return;
+ }
+
+ /* are we already running? if not, do conf_mount_rw(), otherwise it should already be rw */
+ if (!is_subsystem_dirty('sshdkeys')) {
+ conf_mount_rw();
+ }
+
+ $sshConfigDir = "/etc/ssh";
+
+ $keys = array(
+ array('type' => 'rsa1', 'suffix' => ''),
+ array('type' => 'rsa', 'suffix' => 'rsa_'),
+ array('type' => 'dsa', 'suffix' => 'dsa_'),
+ array('type' => 'ecdsa', 'suffix' => 'ecdsa_'),
+ array('type' => 'ed25519', 'suffix' => 'ed25519_')
+ );
+
+ $keyfiles = array();
+ foreach ($keys as $key) {
+ $keyfiles[] = "ssh_host_{$key['suffix']}key";
+ $keyfiles[] = "ssh_host_{$key['suffix']}key.pub";
+ }
+
+ /* restore ssh data for nanobsd platform */
+ if ($g['platform'] == "nanobsd" and file_exists("/conf/sshd/ssh_host_key") and !file_exists("{$sshConfigDir}/ssh_host_key.pub")) {
+ echo "Restoring SSH from /conf/sshd/";
+ exec("/bin/cp -p /conf/sshd/* {$sshConfigDir}/");
+
+ /* make sure host private key permissions aren't too open so sshd won't complain */
+ foreach ($keyfiles as $f2c) {
+ if (file_exists("{$sshConfigDir}/{$f2c}")) {
+ chmod("{$sshConfigDir}/{$f2c}", 0600);
+ }
+ }
+ }
+
+ /* if any of these files are 0 bytes then they are corrupted.
+ * remove them
+ */
+ foreach ($keyfiles as $f2c) {
+ if (!file_exists("{$sshConfigDir}/{$f2c}") || filesize("{$sshConfigDir}/{$f2c}") == 0) {
+ /* Make sure we remove both files */
+ unlink_if_exists($sshConfigDir . '/' . basename($f2c, ".pub"));
+ unlink_if_exists($sshConfigDir . '/' . $f2c);
+ }
+ }
+
+ if (!is_dir("/var/empty")) {
+ /* make ssh home directory */
+ mkdir("/var/empty", 0555);
+ }
+
+ if (!file_exists("/var/log/lastlog")) {
+ /* Login related files. */
+ @touch("/var/log/lastlog");
+ }
+
+ if (is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
+ $sshport = $config['system']['ssh']['port'];
+ } else {
+ $sshport = 22;
+ }
+
+ /* Include default configuration for pfSense */
+ $sshconf = "# This file is automatically generated at startup\n";
+ $sshconf .= "Ciphers aes128-ctr,aes256-ctr,arcfour256,arcfour,aes128-cbc,aes256-cbc\n";
+ $sshconf .= "PermitRootLogin yes\n";
+ $sshconf .= "Compression yes\n";
+ $sshconf .= "ClientAliveInterval 30\n";
+ $sshconf .= "UseDNS no\n";
+ $sshconf .= "X11Forwarding no\n";
+ if (isset($config['system']['ssh']['sshdkeyonly'])) {
+ $sshconf .= "# Login via Key only\n";
+ $sshconf .= "PasswordAuthentication no\n";
+ $sshconf .= "ChallengeResponseAuthentication no\n";
+ $sshconf .= "PubkeyAuthentication yes\n";
+ } else {
+ $sshconf .= "# Login via Key and Password\n";
+ $sshconf .= "PasswordAuthentication yes\n";
+ $sshconf .= "ChallengeResponseAuthentication yes\n";
+ $sshconf .= "PubkeyAuthentication yes\n";
+ }
+ $sshconf .= "# override default of no subsystems\n";
+ $sshconf .= "Subsystem sftp /usr/libexec/sftp-server\n";
+ /* Only allow protocol 2, because we say so */
+ $sshconf .= "Protocol 2\n";
+ /* Run the server on another port if we have one defined */
+ $sshconf .= "Port $sshport\n";
+ /* Hide FreeBSD version */
+ $sshconf .= "VersionAddendum none\n";
+ $sshconf .= "LoginGraceTime 30s\n";
+
+ /* Apply package SSHDCond settings if config file exists */
+ if (file_exists("/etc/sshd_extra")) {
+ $fdExtra = fopen("/etc/sshd_extra", 'r');
+ $szExtra = fread($fdExtra, 1048576); // Read up to 1MB from extra file
+ $sshconf .= $szExtra;
+ fclose($fdExtra);
+ }
+
+ /* Write the new sshd config file */
+ @file_put_contents("{$sshConfigDir}/sshd_config", $sshconf);
+
+ /* mop up from a badly implemented ssh keys -> cf backup */
+ if ($config['ssh']['dsa_key'] <> "") {
+ unset($config['ssh']['dsa_key']);
+ unset($config['ssh']['ecdsa_key']);
+ unset($config['ssh']['ed25519_key']);
+ unset($config['ssh']['rsa_key']);
+ unset($config['ssh']['rsa1_key']);
+ unset($config['ssh']['dsa']);
+ unset($config['ssh']['rsa']);
+ unset($config['ssh']['rsa1']);
+ unset($config['ssh']['ak']);
+ write_config("Clearing SSH keys from config.xml");
+ }
+
+ /* are we already running? if so exit */
+ if (is_subsystem_dirty('sshdkeys')) {
+ unset($keys, $keyfiles);
+ return;
+ }
+
+ // Check for all needed key files. If any are missing, the keys need to be regenerated.
+ $generate_keys = array();
+ foreach ($keys as $key) {
+ if (!file_exists("{$sshConfigDir}/ssh_host_{$key['suffix']}key") ||
+ !file_exists("{$sshConfigDir}/ssh_host_{$key['suffix']}key.pub")) {
+ $generate_keys[] = $key;
+ }
+ }
+
+ if (!empty($generate_keys)) {
+ /* remove previous keys and regen later */
+ file_notice("SSH", "{$g['product_name']} has started creating missing SSH keys. SSH Startup will be delayed. Please note that reloading the filter rules and changes will be delayed until this operation is completed.", "SSH KeyGen", "");
+ mark_subsystem_dirty('sshdkeys');
+ echo " Generating Keys:\n";
+ foreach ($generate_keys as $key) {
+ $_gb = exec("/usr/bin/nice -n20 /usr/bin/ssh-keygen -t {$key['type']} -N '' -f {$sshConfigDir}/ssh_host_{$key['suffix']}key");
+ }
+ clear_subsystem_dirty('sshdkeys');
+ file_notice("SSH", "{$g['product_name']} has completed creating your SSH keys. SSH is now started.", "SSH Startup", "");
+ }
+
+ /* kill existing sshd process, server only, not the childs */
+ $sshd_pid = exec("ps ax | egrep '/usr/sbin/[s]shd' | awk '{print $1}'");
+ if ($sshd_pid <> "") {
+ echo "stopping ssh process $sshd_pid \n";
+ @posix_kill($sshd_pid, SIGTERM);
+ }
+ /* Launch new server process */
+ $status = mwexec("/usr/sbin/sshd");
+ if ($status <> 0) {
+ file_notice("sshd_startup", "SSHD failed to start.", "SSHD Daemon", "");
+ echo "error!\n";
+ } else {
+ echo "done.\n";
+ }
+
+ // NanoBSD
+ if ($g['platform'] == "nanobsd") {
+ if (!is_dir("/conf/sshd")) {
+ mkdir("/conf/sshd", 0750);
+ }
+ $_gb = exec("/bin/cp -p {$sshConfigDir}/ssh_host* /conf/sshd");
+ }
+ conf_mount_ro();
+ unset($keys, $keyfiles);
+?>
diff --git a/src/etc/ssl/openssl.cnf b/src/etc/ssl/openssl.cnf
new file mode 100644
index 0000000..41664e6
--- /dev/null
+++ b/src/etc/ssl/openssl.cnf
@@ -0,0 +1,309 @@
+# $FreeBSD: src/crypto/openssl/apps/openssl.cnf,v 1.6 2004/03/17 17:44:38 nectar Exp $
+#
+# OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+#
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+# default SAN value if $ENV::SAN is not defined
+#
+SAN =
+
+# Extra OBJECT IDENTIFIER info:
+#oid_file = $ENV::HOME/.oid
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+
+# We can add new OIDs in here for use by 'ca' and 'req'.
+# Add a simple OID like this:
+# testoid1=1.2.3.4
+# Or use config file substitution like this:
+# testoid2=${testoid1}.5.6
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = ./demoCA # Where everything is kept
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+#unique_subject = no # Set to 'no' to allow creation of
+ # several certificates with same subject.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+#crlnumber = $dir/crlnumber # the current crl number
+ # must be commented out to leave a V1 CRL
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem# The private key
+RANDFILE = $dir/private/.rand # private random number file
+
+x509_extensions = usr_cert # The extensions to add to the cert
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+crl_extensions = crl_ext
+
+default_days = 365 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = md5 # which md to use.
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+distinguished_name=req_distinguished_name
+req_extensions = v3_req
+prompt=no
+
+default_bits = 2048
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+#input_password=""
+#output_password=""
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = US
+#countryName_default = AU
+#countryName_min = 2
+#countryName_max = 2
+
+stateOrProvinceName = Somewhere
+#stateOrProvinceName_default = Somestate
+
+localityName = Somecity
+
+0.organizationName = CompanyName
+#0.organizationName_default = SampleNameDefault
+
+# we can do this but it is not needed normally :-)
+#1.organizationName = Second Organization Name (eg, company)
+#1.organizationName_default = World Wide Web Pty Ltd
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+#organizationalUnitName_default =
+
+commonName = Common Name (eg, YOUR name)
+#commonName_max = 64
+
+emailAddress = Email Address
+#emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+
+unstructuredName = An optional company name
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+# nsCertType = server
+
+# For an object signing certificate this would be used.
+# nsCertType = objsign
+
+# For normal client use this is typical
+# nsCertType = client, email
+
+# and for everything including object signing:
+# nsCertType = client, email, objsign
+
+# This is typical in keyUsage for a client certificate.
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "OpenSSL Generated User Certificate"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+extendedKeyUsage=clientAuth
+
+# This stuff is for subjectAltName and issuerAltname.
+# Import the email address.
+# subjectAltName=email:copy
+# An alternative to produce certificates that aren't
+# deprecated according to PKIX.
+# subjectAltName=email:move
+
+# Copy subject details
+# issuerAltName=issuer:copy
+
+#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+[ usr_cert_san ]
+
+# copy of [ usr_cert ] plus nonempty Subject Alternative Names
+basicConstraints=CA:FALSE
+nsComment = "OpenSSL Generated User Certificate"
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+extendedKeyUsage=clientAuth
+subjectAltName=$ENV::SAN
+
+[ server ]
+
+# Make a cert with nsCertType=server
+basicConstraints=CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+extendedKeyUsage=serverAuth,1.3.6.1.5.5.8.2.2
+keyUsage = digitalSignature, keyEncipherment
+
+[ server_san ]
+
+# copy of [ server ] plus nonempty Subject Alternative Names
+basicConstraints=CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+extendedKeyUsage=serverAuth,1.3.6.1.5.5.8.2.2
+keyUsage = digitalSignature, keyEncipherment
+subjectAltName=$ENV::SAN
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+
+# PKIX recommendation.
+
+subjectKeyIdentifier=hash
+
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate.
+keyUsage = cRLSign, keyCertSign
+
+# Some might want this also
+# nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+# subjectAltName=email:copy
+# Copy issuer details
+# issuerAltName=issuer:copy
+
+# DER hex encoding of an extension: beware experts only!
+# obj=DER:02:03
+# Where 'obj' is a standard or added object
+# You can even override a supported extension:
+# basicConstraints= critical, DER:30:03:01:01:FF
+
+[ v3_ca_san ]
+
+# copy of [ v3_ca ] plus nonempty Subject Alternative Names
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints = CA:true
+subjectAltName=$ENV::SAN
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/src/etc/syslog.conf b/src/etc/syslog.conf
new file mode 100644
index 0000000..6f29538
--- /dev/null
+++ b/src/etc/syslog.conf
@@ -0,0 +1,12 @@
+local0.* %/var/log/filter.log
+local3.* %/var/log/vpn.log
+local4.* %/var/log/portalauth.log
+local7.* %/var/log/dhcpd.log
+local7.none %/var/log/system.log
+kern.debug;lpr.info;mail.crit; %/var/log/system.log
+news.err;local3.none;local4.none; %/var/log/system.log
+*.notice; %/var/log/system.log
+local0.none;daemon.info %/var/log/system.log
+daemon.info;security.* %/var/log/ipsec.log
+auth.info;authpriv.info %/var/log/system.log
+auth.info;authpriv.info |exec /usr/local/sbin/sshlockout_pf
diff --git a/src/etc/ttys b/src/etc/ttys
new file mode 100644
index 0000000..382c6a7
--- /dev/null
+++ b/src/etc/ttys
@@ -0,0 +1,49 @@
+#
+# $FreeBSD: stable/10/etc/etc.amd64/ttys 267236 2014-06-08 17:50:07Z nwhitehorn $
+# @(#)ttys 5.1 (Berkeley) 4/17/89
+#
+# This file specifies various information about terminals on the system.
+# It is used by several different programs. Common entries for the
+# various columns include:
+#
+# name The name of the terminal device.
+#
+# getty The program to start running on the terminal. Typically a
+# getty program, as the name implies. Other common entries
+# include none, when no getty is needed, and xdm, to start the
+# X Window System.
+#
+# type The initial terminal type for this port. For hardwired
+# terminal lines, this will contain the type of terminal used.
+# For virtual consoles, the correct type is typically xterm.
+# Other common values include dialup for incoming modem ports, and
+# unknown when the terminal type cannot be predetermined.
+#
+# status Must be on or off. If on, init will run the getty program on
+# the specified port. If the word "secure" appears, this tty
+# allows root login.
+#
+# name getty type status comments
+#
+# If console is marked "insecure", then init will ask for the root password
+# when going to single-user mode.
+console none unknown off secure
+#
+ttyv0 "/usr/libexec/getty al.Pc" cons25 on secure
+# Virtual terminals
+ttyv1 "/usr/libexec/getty Pc" xterm off secure
+ttyv2 "/usr/libexec/getty Pc" xterm off secure
+ttyv3 "/usr/libexec/getty Pc" xterm off secure
+ttyv4 "/usr/libexec/getty Pc" xterm off secure
+ttyv5 "/usr/libexec/getty Pc" xterm off secure
+ttyv6 "/usr/libexec/getty Pc" xterm off secure
+ttyv7 "/usr/libexec/getty Pc" xterm off secure
+ttyv8 "/usr/local/bin/xdm -nodaemon" xterm off secure
+# Serial terminals
+# The 'dialup' keyword identifies dialin lines to login, fingerd etc.
+ttyu0 "/usr/libexec/getty al.115200" cons25 onifconsole secure
+ttyu1 "/usr/libexec/getty al.115200" cons25 onifconsole secure
+ttyu2 "/usr/libexec/getty al.115200" cons25 onifconsole secure
+ttyu3 "/usr/libexec/getty al.115200" cons25 onifconsole secure
+# Dumb console
+dcons "/usr/libexec/getty std.9600" vt100 off secure
diff --git a/src/etc/version b/src/etc/version
new file mode 100644
index 0000000..d5221db
--- /dev/null
+++ b/src/etc/version
@@ -0,0 +1 @@
+2.3-DEVELOPMENT
OpenPOWER on IntegriCloud