diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 0291dfda..bc66ecfe 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -158,6 +158,9 @@ const internalNginx = { let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id}, {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits}, {allow_websocket_upgrade: host.allow_websocket_upgrade}, {enable_proxy_protocol: host.enable_proxy_protocol}, + {stream_enable_proxy_protocol: host.stream_enable_proxy_protocol}, + {stream_allow_proxy_protocol: host.stream_allow_proxy_protocol}, + {stream_load_balancer_ip: host.stream_load_balancer_ip}, {load_balancer_ip: host.load_balancer_ip}, {http2_support: host.http2_support}, {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list}, {certificate: host.certificate}, host.locations[i]); diff --git a/backend/migrations/22021009153423_proxy_protocol.js b/backend/migrations/22021009153423_proxy_protocol.js index a780f531..b82e0711 100644 --- a/backend/migrations/22021009153423_proxy_protocol.js +++ b/backend/migrations/22021009153423_proxy_protocol.js @@ -12,15 +12,21 @@ const logger = require('../logger').migrate; */ exports.up = function (knex/*, Promise*/) { logger.info('[' + migrate_name + '] Migrating Up...'); - - return knex.schema.table('proxy_host', function (proxy_host) { + let ret = knex.schema.table('proxy_host', function (proxy_host) { proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); proxy_host.string('load_balancer_ip').notNull().defaultTo(''); }) .then(() => { logger.info('[' + migrate_name + '] proxy_host Table altered - PROXY protocol added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] Error migrating up: ' + err); + ret = Promise.resolve(true); }); - + if (!ret) { + logger.error('[' + migrate_name + '] ERROR MIGRATING UP'); + ret = Promise.resolve(true); + } + return ret; }; /** diff --git a/backend/migrations/22021010135303_stream_proxy_protocol.js b/backend/migrations/22021010135303_stream_proxy_protocol.js new file mode 100644 index 00000000..4f102a2d --- /dev/null +++ b/backend/migrations/22021010135303_stream_proxy_protocol.js @@ -0,0 +1,49 @@ +const migrate_name = 'stream_proxy_protocol'; +const logger = require('../logger').migrate; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.up = function (knex/*, Promise*/) { + logger.info('[' + migrate_name + '] Migrating Up...'); + let ret = knex.schema.table('stream', function (stream) { + stream.integer('stream_enable_proxy_protocol').notNull().unsigned().defaultTo(0); + stream.integer('stream_access_proxy_protocol').notNull().unsigned().defaultTo(0); + stream.string('stream_load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - PROXY protocol added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] Error migrating up: ' + err); + }); + if (!ret) { + logger.error('[' + migrate_name + '] ERROR MIGRATING UP'); + } +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex/*, Promise*/) { + return knex.schema.table('stream', (stream) => { + stream.dropColumn('stream_enable_proxy_protocol'); + stream.dropColumn('stream_access_proxy_protocol'); + stream.dropColumn('stream_load_balancer_ip'); + }) + .then(function () { + logger.info('[' + migrate_name + '] MIGRATING DOWN stream Table altered - PROXY protocol removed'); + }); + + // logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); + // return Promise.resolve(true); +}; \ No newline at end of file diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json index 27a8ec2a..74392aa5 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -59,11 +59,12 @@ "type": "boolean" }, "enable_proxy_protocol": { - "description": "Enable PROXY Protocol support", + "description": "Enable PROXY Protocol support (Pass through)", "example": true, "type": "boolean" }, "load_balancer_ip": { + "description": "Authorized TCP Load Balancer IP / CIDR for setting 'set_real_ip_from'", "type": "string", "minLength": 0, "maxLength": 255 diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json index 159c8036..f91ef406 100644 --- a/backend/schema/endpoints/streams.json +++ b/backend/schema/endpoints/streams.json @@ -46,6 +46,22 @@ "udp_forwarding": { "type": "boolean" }, + "stream_enable_proxy_protocol": { + "description": "Enable PROXY Protocol creation and override", + "example": true, + "type": "boolean" + }, + "stream_allow_proxy_protocol": { + "description": "Enable PROXY Protocol passthrough", + "example": true, + "type": "boolean" + }, + "stream_load_balancer_ip": { + "description": "Authorized TCP Load Balancer IP / CIDR for setting 'set_real_ip_from'", + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "enabled": { "$ref": "../definitions.json#/definitions/enabled" }, @@ -78,6 +94,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "enabled": { "$ref": "#/definitions/enabled" }, @@ -88,7 +113,7 @@ "links": [ { "title": "List", - "description": "Returns a list of Steams", + "description": "Returns a list of Streams", "href": "/nginx/streams", "access": "private", "method": "GET", @@ -137,6 +162,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -177,6 +211,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -190,7 +233,7 @@ }, { "title": "Delete", - "description": "Deletes a existing Stream", + "description": "Deletes an existing Stream", "href": "/nginx/streams/{definitions.identity.example}", "access": "private", "method": "DELETE", @@ -204,7 +247,7 @@ }, { "title": "Enable", - "description": "Enables a existing Stream", + "description": "Enables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/enable", "access": "private", "method": "POST", @@ -218,7 +261,7 @@ }, { "title": "Disable", - "description": "Disables a existing Stream", + "description": "Disables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/disable", "access": "private", "method": "POST", diff --git a/backend/templates/_stream_proxy_protocol.conf b/backend/templates/_stream_proxy_protocol.conf new file mode 100644 index 00000000..7275e4e5 --- /dev/null +++ b/backend/templates/_stream_proxy_protocol.conf @@ -0,0 +1,5 @@ +{%if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true %} +{% if stream_load_balancer_ip != '' %} + set_real_ip_from {{ stream_load_balancer_ip }}; +{% endif %} +{% endif %} diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 76159a64..5cce27cf 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -5,13 +5,16 @@ {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { - listen {{ incoming_port }}; + listen {{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% if ipv6 -%} - listen [::]:{{ incoming_port }}; + listen [::]:{{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% else -%} #listen [::]:{{ incoming_port }}; {% endif %} - +{%if stream_enable_proxy_protocol == 1 or stream_enable_proxy_protocol == true%} + proxy_protocol on; +{% endif %} + {% include '_stream_proxy_protocol.conf' %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; # Custom diff --git a/frontend/js/app/nginx/stream/form.ejs b/frontend/js/app/nginx/stream/form.ejs index eb80c373..ab669b79 100644 --- a/frontend/js/app/nginx/stream/form.ejs +++ b/frontend/js/app/nginx/stream/form.ejs @@ -42,6 +42,32 @@ +
+
+ +
+
+
+
+ +
+
+
+
+ + > +
+
+ +
<%- i18n('streams', 'forward-type-error') %>
diff --git a/frontend/js/app/nginx/stream/form.js b/frontend/js/app/nginx/stream/form.js index be8fc8bc..9dedd6b7 100644 --- a/frontend/js/app/nginx/stream/form.js +++ b/frontend/js/app/nginx/stream/form.js @@ -18,13 +18,23 @@ module.exports = Mn.View.extend({ buttons: '.modal-footer button', switches: '.custom-switch-input', cancel: 'button.cancel', - save: 'button.save' + save: 'button.save', + stream_allow_proxy_protocol: 'input[name="stream_allow_proxy_protocol"]', + stream_enable_proxy_protocol: 'input[name="stream_enable_proxy_protocol"]', + stream_load_balancer_ip: 'input[name="stream_load_balancer_ip"]' }, events: { 'change @ui.switches': function () { this.ui.type_error.hide(); }, + 'change @ui.stream_allow_proxy_protocol': function () { + let checked = this.ui.stream_allow_proxy_protocol.prop('checked'); + this.ui.stream_load_balancer_ip + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, 'click @ui.save': function (e) { e.preventDefault(); @@ -47,6 +57,8 @@ module.exports = Mn.View.extend({ data.forwarding_port = parseInt(data.forwarding_port, 10); data.tcp_forwarding = !!data.tcp_forwarding; data.udp_forwarding = !!data.udp_forwarding; + data.stream_enable_proxy_protocol = !!data.stream_enable_proxy_protocol; + data.stream_allow_proxy_protocol = !!data.stream_allow_proxy_protocol; let method = App.Api.Nginx.Streams.create; let is_new = true; @@ -82,3 +94,4 @@ module.exports = Mn.View.extend({ } } }); + diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 6be8d712..737938f8 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -134,8 +134,8 @@ "ignore-invalid-upstream-ssl": "Ignore Invalid SSL", "custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/", "search": "Search Host…", - "enable-proxy-protocol": "Enable PROXY Protocol", - "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range " + "enable-proxy-protocol": "Allow PROXY Protocol (Pass through)", + "load-balancer-ip": "AUTHORIZED Load balancer or TCP proxy IP / CIDR range" }, "redirection-hosts": { "title": "Redirection Hosts", @@ -181,7 +181,10 @@ "delete-confirm": "Are you sure you want to delete this Stream?", "help-title": "What is a Stream?", "help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.", - "search": "Search Incoming Port…" + "search": "Search Incoming Port…", + "allow-proxy-protocol": "Allow PROXY Protocol (Pass through)", + "enable-proxy-protocol": "Enable PROXY Protocol (Create and override PROXY protocol instead of passing through)", + "load-balancer-ip": "AUTHORIZED Load balancer or TCP proxy IP / CIDR range" }, "certificates": { "title": "SSL Certificates", diff --git a/frontend/js/models/stream.js b/frontend/js/models/stream.js index ba035429..dd238b39 100644 --- a/frontend/js/models/stream.js +++ b/frontend/js/models/stream.js @@ -13,6 +13,9 @@ const model = Backbone.Model.extend({ forwarding_port: null, tcp_forwarding: true, udp_forwarding: false, + stream_allow_proxy_protocol: false, + stream_enable_proxy_protocol: false, + stream_load_balancer_ip: '', enabled: true, meta: {}, // The following are expansions: