firewing1's bloghttp://www.firewing1.com/blogs/firewing1
enPolicy-based routing on Linux to forward packets from a subnet or process through a VPNhttp://www.firewing1.com/blog/2018/02/15/policy-based-routing-linux-forward-packets-subnet-or-process-through-vpn
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>In my <a href="http://www.firewing1.com/blog/2017/11/12/routing-packets-vlan-through-vpn-ubiquity-routers">last post</a>, I covered how to route packages from a specific VLAN through a VPN on the USG. Here, I will show how to use policy-based routing on Linux to route packets from specific processes or subnets through a VPN connection on a Linux host in your LAN instead. You could then point to this host as the next-hop for a VLAN on your USG to achieve the same effect as in my last post.</p>
<p>Note that this post will assume a modern tooling including <code>firewalld</code> and <code>NetworkManager</code>, and that subnet <code>192.168.10.0/24</code> is your LAN. This post will send packets coming from <code>192.168.20.0/24</code> to VPN, but you could customize that as you see fit (e.g. send specific only hosts from your normal LAN subnet instead).</p>
<h3>VPN network interface setup</h3>
<p>First, let's create a VPN firewalld zone so we can easily apply firewall rules just to the VPN connection:</p>
<pre><code>firewall-cmd --permanent --new-zone=VPN
firewall-cmd --reload
</code></pre><p>Next, create the VPN interface with NetworkManager:</p>
<pre><code>VPN_USER=openvpn_username
VPN_PASSWORD=openvpn_password
# Setup VPN connection with NetworkManager
dnf install -y NetworkManager-openvpn
nmcli c add type vpn ifname vpn con-name vpn vpn-type openvpn
nmcli c mod vpn connection.zone "VPN"
nmcli c mod vpn connection.autoconnect "yes"
nmcli c mod vpn ipv4.method "auto"
nmcli c mod vpn ipv6.method "auto"
# Ensure it is never set as default route, nor listen to its DNS settings
# (doing so would push the VPN DNS for all lookups)
nmcli c mod vpn ipv4.never-default "yes"
nmcli c mod vpn ipv4.ignore-auto-dns on
nmcli c mod vpn ipv6.never-default "yes"
nmcli c mod vpn ipv6.ignore-auto-dns on
# Set configuration options
nmcli c mod vpn vpn.data "comp-lzo = adaptive, ca = /etc/openvpn/keys/vpn-ca.crt, password-flags = 0, connection-type = password, remote = remote.vpnhost.tld, username = $VPN_USER, reneg-seconds = 0"
# Configure VPN secrets for passwordless start
cat &lt;&lt; EOF &gt;&gt; /etc/NetworkManager/system-connections/vpn
[vpn-secrets]
password=$VPN_PASSWORD
EOF
systemctl restart NetworkManager
</code></pre><h3>Configure routing table and policy-based routing</h3>
<p>Normally, a host has a single routing table and therefore only 1 default gateway. Static routes can be configured for next-hops, this is configuring the system to route based a packet's <em>destination</em> address, and we want to know how route based on the <em>source</em> address of a packet. For this, we need multiple routing tables (one for normal traffic, another for VPN traffic) and Policy Based Routing (PBR) to define rules on how to select the right one.</p>
<p>First, let's create a second routing table for VPN connections:</p>
<pre><code>cat &lt;&lt; EOF &gt;&gt; /etc/iproute2/rt_tables
100 vpn
EOF
</code></pre><p>Next, setup an IP rule to select between routing tables for incoming packets based on their source addres:</p>
<pre><code># Replace this with your LAN interface
IFACE=eno1
# Route incoming packets on VPN subnet towards VPN interface
cat &lt;&lt; EOF &gt;&gt; /etc/sysconfig/network-scripts/rule-$IFACE
from 192.168.20.0/24 table vpn
EOF
</code></pre><p>Now that we can properly select which routing table to use, we need to configure routes on the <code>vpn</code> routing table:</p>
<pre><code>cat &lt;&lt; EOF &gt; /etc/sysconfig/network-scripts/route-$IFACE
# Always allow LAN connectivity
192.168.10.0/24 dev $IFACE scope link metric 98 table vpn
192.168.20.0/24 dev $IFACE scope link metric 99 table vpn
# Blackhole by default to avoid privacy leaks if VPN disconnects
blackhole 0.0.0.0/0 metric 100 table vpn
EOF
</code></pre><p>You'll note that nowhere do we actually define the default gateway - because we can't <em>yet</em>. VPN connections often dynamically allocate IPs, so we'll need to configure the default route for the VPN table to match that particular IP each time we start the VPN connection (we'll do so with a smaller <code>metric</code> figure than the blackhole above of <code>100</code>, thereby avoiding the blackhole rule).</p>
<p>So, we will configure NetworkManager to trigger a script upon bringing up the VPN interface:</p>
<pre><code>cat &lt;&lt; EOF &gt; /etc/NetworkManager/dispatcher.d/90-vpn
VPN_UUID="\$(nmcli con show vpn | grep uuid | tr -s ' ' | cut -d' ' -f2)"
INTERFACE="\$1"
ACTION="\$2"
if [ "\$CONNECTION_UUID" == "\$VPN_UUID" ];then
/usr/local/bin/configure_vpn_routes "\$INTERFACE" "\$ACTION"
fi
EOF
</code></pre><p>In that script, we will read the IP address of the VPN interface and install it as the default route. When the VPN is deactivated, we'll do the opposite and cleanup the route we added:</p>
<pre><code>cat &lt;&lt; EOF &gt; /usr/local/bin/configure_vpn_routes
#!/bin/bash
# Configures a secondary routing table for use with VPN interface
interface=\$1
action=\$2
tables=/etc/iproute2/rt_tables
vpn_table=vpn
zone="\$(nmcli -t --fields connection.zone c show vpn | cut -d':' -f2)"
clear_vpn_routes() {
table=$1
/sbin/ip route show via 192.168/16 table \$table | while read route;do
/sbin/ip route delete \$route table \$table
done
}
clear_vpn_rules() {
keep=\$(ip rule show from 192.168/16)
/sbin/ip rule show from 192.168/16 | while read line;do
rule="\$(echo \$line | cut -d':' -f2-)"
(echo "\$keep" | grep -q "\$rule") &amp;&amp; continue
/sbin/ip rule delete \$rule
done
}
if [ "\$action" = "vpn-up" ];then
ip="\$(/sbin/ip route get 8.8.8.8 oif \$interface | head -n 1 | cut -d' ' -f5)"
# Modify default route
clear_vpn_routes \$vpn_table
/sbin/ip route add default via \$ip dev \$interface table \$vpn_table
elif [ "\$action" = "vpn-down" ];then
# Remove VPN routes
clear_vpn_routes \$vpn_table
fi
EOF
chmod 755 /usr/local/bin/configure_vpn_routes
</code></pre><p>Bring up the VPN interface:</p>
<pre><code>nmcli c up vpn
</code></pre><p>That's all, enjoy!</p>
<h3>Sending all packets from a user through the VPN</h3>
<p>I find this technique particularly versatile as one can also easily force all traffic from a particular user through the VPN tunnel:</p>
<pre><code># Replace this with your LAN interface
IFACE=eno1
# Send any marked packets using VPN routing table
cat &lt;&lt; EOF &gt;&gt; /etc/sysconfig/network-scripts/rule-$IFACE
fwmark 0x50 table vpn
EOF
# Mark all packets originating from processes owned by this user
firewall-cmd --permanent --direct --add-rule ipv4 mangle OUTPUT 0 -m owner --uid-owner LINUXUSER -j MARK --set-mark 0x50
# Enable masquerade on the VPN zone (enables IP forwarding between interfaces)
firewall-cmd --permanent --add-masquerade --zone=VPN
firewall-cmd --reload
</code></pre><p>Note 0x50 is arbitrary, as long as it the rule and firewall rule match, you're fine.</p></div></div></div><span class="submitted-by">Posted on Thu, 2018/02/15 - 12:32am</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Policy-based routing on Linux to forward packets from a subnet or process through a VPN - stewart a." addthis:url="http://www.firewing1.com/blog/2018/02/15/policy-based-routing-linux-forward-packets-subnet-or-process-through-vpn"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/unifi">unifi</a></div><div class="field-item odd"><a href="/blog/tag/networking">networking</a></div><div class="field-item even"><a href="/taxonomy/term/43">linux</a></div><div class="field-item odd"><a href="/blog/tag/vpn">vpn</a></div></div></div>Thu, 15 Feb 2018 05:32:10 +0000firewing1647 at http://www.firewing1.comhttp://www.firewing1.com/blog/2018/02/15/policy-based-routing-linux-forward-packets-subnet-or-process-through-vpn#commentsRouting packets from a VLAN through a VPN with Ubiquity routershttp://www.firewing1.com/blog/2017/11/12/routing-packets-vlan-through-vpn-ubiquity-routers
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>A little while back, I posted <a href="https://www.reddit.com/r/Ubiquiti/comments/645kw6/howto_traffic_from_subnet_to_vpn_using_policy/">this</a> on Reddit about setting up a Ubiquity Unifi Security Gateway (USG) or Edge Router Lite (ERL) to selectively route packets through a VPN interface; I wanted to elaborate a bit on the setup for this.</p>
<h3>The goal</h3>
<p>The goal was have my Unifi device establish two networks, one that behaves normally and another that routes all traffic through a VPN interface automatically. The value prop for a setup like this is that you can avoid having to configure each device &amp; the VPN on each separately; simply connect to the network and that's it. It's simple, uses a single VPN connection for multiple devices and even lets friends &amp; family use it easily with zero configuration.</p>
<p>In my case, I setup a second SSID and tied to different subnet (tagged VLAN) so simply by switching networks, you could gain VPN protection. Normally, this is very difficult to do because the router has a single default route; all packets not destined for local networks will exit using said default route.</p>
<p>This technique is made possible through the use of policy-based routing, which establishes multiple routing tables and rules on when to use a given table. This permits the router to determine the next-hop based on the source address, not the destination address.</p>
<h3>Configuration</h3>
<p>Here are some the basic steps to getting your USG configured:</p>
<pre><code># Setup route using table #1 with next-hop as VPN, blackhole if VPN is down
set protocols static table 1 route 0.0.0.0/0 blackhole distance 100
set protocols static table 1 interface-route 0.0.0.0/0 next-hop-interface vtun0 distance 2
# Set rules for when to send packets using routes from table 1
set firewall modify SOURCE_ROUTE rule 10 description "Traffic from VLAN 11 to VPN"
set firewall modify SOURCE_ROUTE rule 10 source address 192.168.20.0/24
set firewall modify SOURCE_ROUTE rule 10 modify table 1
set firewall modify SOURCE_ROUTE rule 10 action modify
# Apply the rule
set interfaces ethernet eth1 vif 11 firewall in modify SOURCE_ROUTE
commit
save
</code></pre><p>As long as the Ubiquity router is the default gateway (it should be if it's serving DHCP), machines on network <code>192.168.20.0/24</code> will now automatically route packets through the USG and then the USG will pick the <code>vtun0</code> interface as its next-hop for those packets. Packets from other sources (e.g. your regular LAN) are routed normally through the WAN link.</p>
<p>Note that you can also set the next-hop to a host, by using this static route instead of the one above (note removal of the blackhole - you'll need to do that on the host specified in next-hop to avoid privacy leaks):</p>
<pre><code># Setup route table #2 with next-hop as VPN via local server
set protocols static table 1 route 0.0.0.0/0 next-hop 192.168.20.100
</code></pre><p>This is useful if you have a home server connected to VPN, and want to route packets through its VPN connection instead of the USG (some additional setup required; <a href="http://www.firewing1.com/blog/2018/02/15/policy-based-routing-linux-forward-packets-subnet-or-process-through-vpn">more on that in this post</a>).</p>
<h3>Troubleshooting</h3>
<p>If this setup does not work as expected, the easiest way to troubleshoot is to verify connectivity. tcpdump will be your best friend here. Something like <code>tcpdump -i interface -A port 80</code> will trace all HTTP traffic on the <code>interface</code> supplied, and</p>
<p>You'll want to verify connectivity in this order:</p>
<h4>1. Verify source packets leave a host</h4>
<p>Use any machine on the 192.168.20.0/24 network to test and start generating some traffic, ensuring the packets do hit the network. You can use something simple like <code>curl google.com</code> to trigger some traffic, and monitor the network interface with <code>tcpdump</code> per above to make sure the packets are sent out.</p>
<h4>2. Verify packets are reaching your next-hop</h4>
<p>Your next-hop is probably the USG/ERL router, but could also be an IP on your network as well. Now that we've confirmed packets are <em>leaving</em>, make sure they are <em>arriving</em> by inspecting the LAN-side interface on your configured next-hop.</p>
<p>Connect over SSH to the next hop (if it's a USG/ERL read <a href="https://help.ubnt.com/hc/en-us/articles/218850057-Intro-to-Networking-How-to-Establish-a-Connection-Using-SSH">this</a>) and run <code>sudo -i</code>. Use <code>ip a</code> to list all interfaces &amp; configured IPs; this should let you pick out the interface name associated to an IP on the <code>192.168.20.0/24</code> network.</p>
<p>Now run <code>tcpdump</code> against that interface and then generate some traffic on the test host from step 1. Do you see them arriving?</p>
<h4>3. Verify packets are exiting your next-hop on the VPN interface</h4>
<p>If you've made it this far packets arrive on your next-hop so let's make sure it's forwarding out through the right interface. First, list all configured policy-based routing rules with <code>ip rule</code> - you should expect to see 0 (default table) and 1 (for certain marked packets). List out each routing table using <code>ip rule show table X</code> to make sure things look as you'd expect. For example, <code>ip route show table 1</code>:</p>
<pre><code>default dev vtun0 scope link
blackhole default metric 100
</code></pre><p>Or if you configured next-hop as a host instead:</p>
<pre><code>default via 192.168.20.100 dev eth1.11
</code></pre><p>Now run tcpdump on the shown interface and verify if packets are existing as expected.</p>
<h3>Note for Unifi users</h3>
<p>Lastly, note that if you use a USG instead of a ERL, these settings will not be persisted. Your settings will be overwritten by Unifi Controller after any provision or reboot operation -- you will need to manually persist them by <a href="https://help.ubnt.com/hc/en-us/articles/215458888-UniFi-How-to-further-customize-USG-configuration-with-config-gateway-json">exporting to a config.gateway.json file</a>.</p></div></div></div><span class="submitted-by">Posted on Sun, 2017/11/12 - 8:00pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Routing packets from a VLAN through a VPN with Ubiquity routers - stewart a." addthis:url="http://www.firewing1.com/blog/2017/11/12/routing-packets-vlan-through-vpn-ubiquity-routers"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/unifi">unifi</a></div><div class="field-item odd"><a href="/blog/tag/networking">networking</a></div><div class="field-item even"><a href="/blog/tag/vpn">vpn</a></div></div></div>Mon, 13 Nov 2017 01:00:35 +0000firewing1646 at http://www.firewing1.comhttp://www.firewing1.com/blog/2017/11/12/routing-packets-vlan-through-vpn-ubiquity-routers#commentsConfiguring multiple DHCP reservations [fixed IPs] for the same host with a Unifi Security Gatewayhttp://www.firewing1.com/blog/2017/04/09/configuring-multiple-dhcp-reservations-fixed-ips-same-host-unifi-security-gateway
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>I just picked up some new networking gear, so this will be the first of a multi-part blog post about my learnings configuring Unifi gear.</p>
<p>One issue I noticed right away was that it is not possible, via CLI nor GUI, to configure fixed IP address for a host that relies on more than 1 of the configured networks/VLANs. Since I have a home server (user VLAN) that is also hosting the controller softare (management VLAN) and also acts as a gateway for sending packets over its VPN interface (VPN VLAN), this was necessary for me.</p>
<p>It is possible but requires a bit of manual configuration using a <a href="https://help.ubnt.com/hc/en-us/articles/215458888-UniFi-How-to-further-customize-USG-configuration-with-config-gateway-json">config.gateway.json file</a>. First, if you have configured a fixed IP for the host, unset it.</p>
<p>Then, merge in the DHCP mappings in your <code>config.gateway.json</code> file:</p>
<pre><code>{
"service":{
"dhcp-server":{
"shared-network-name":{
"LAN_192.168.1.0-24":{
"subnet":{
"192.168.1.0/24":{
"static-mapping":{
"00-aa-22-bb-44-cc.mgmt":{
"ip-address":"192.168.1.5",
"mac-address":"00:aa:22:bb:44:cc"
}
}
}
}
},
"LAN_Users_192.168.10.0-24":{
"subnet":{
"192.168.10.0/24":{
"static-mapping":{
"00-aa-22-bb-44-cc.users":{
"ip-address":"192.168.10.5",
"mac-address":"00:aa:22:bb:44:cc"
}
}
}
}
},
"LAN_VPN_192.168.20.0-24":{
"subnet":{
"192.168.20.0/24":{
"static-mapping":{
"00-aa-22-bb-44-cc.vpn":{
"ip-address":"192.168.20.5",
"mac-address":"00:aa:22:bb:44:cc"
}
}
}
}
}
}
}
}
}
</code></pre><p>The key here is that the string child of the <code>static-mapping</code> node <em>must be unique</em>. Unifi will put in the MAC separated by dashes by default, so above I just tacked on the VLAN name to each name.</p>
<p>Re-provision your USG and you should be good to go. If you run into trouble an want to debug DHCP req/ack sequences, setup verbose logging:</p>
<pre><code>configure
set service dhcp-server global-parameters 'log-facility local2;'
set system syslog file dhcpd facility local2 level debug
set system syslog file dhcpd archive files 5
set system syslog file dhcpd archive size 5000
commit
</code></pre><p>You'll find the DHCP log under <code>/var/log/user/dhcpd</code>. Simply reboot to go back to normal logging.</p></div></div></div><span class="submitted-by">Posted on Sun, 2017/04/09 - 3:03am</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Configuring multiple DHCP reservations [fixed IPs] for the same host with a Unifi Security Gateway - stewart a." addthis:url="http://www.firewing1.com/blog/2017/04/09/configuring-multiple-dhcp-reservations-fixed-ips-same-host-unifi-security-gateway"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/unifi">unifi</a></div><div class="field-item odd"><a href="/blog/tag/ubiquiti">ubiquiti</a></div><div class="field-item even"><a href="/blog/tag/networking">networking</a></div></div></div>Sun, 09 Apr 2017 07:03:26 +0000firewing1645 at http://www.firewing1.comhttp://www.firewing1.com/blog/2017/04/09/configuring-multiple-dhcp-reservations-fixed-ips-same-host-unifi-security-gateway#commentsConnecting Azure IoT Hub to Azure Functions and other Event-Hub compatible serviceshttp://www.firewing1.com/blog/2017/01/31/connecting-azure-iot-hub-azure-functions-and-other-event-hub-compatible-services
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>IoT Hub is a great, scalable way to manage your IoT devices. Did you know you can trigger an Azure Function when receiving a device-to-cloud message the same way you can for an Event Hub message?</p>
<h2>Building the Event Hub connection string</h2>
<p>Every IoT hub offers a <a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messaging#read-device-to-cloud-messages">read-only Event Hub-compatible endpoint</a> that can be used with normal Event Hub consumers. This includes Azure Functions, which provides an <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-hubs">Event Hub trigger</a>.</p>
<p>You can view your IoT Hub's Event Hub-compatible by opening your IoT Hub resource in the <a href="https://portal.azure.com">Azure portal</a> and navigating to the <em>Endpoints</em> blade, then clicking the <strong>Events</strong> (<em>messages/events</em>) endpoint. You will find the Event Hub-compatible name, and Event Hub-compatible endpoint (in the format of <code>sb://iothub-ns-foo.servicebus.windows.net/</code>) - keep note of these for later.</p>
<p><img src="http://www.firewing1.com/images/2017-01-iothub-eventhub/iothub-compatible_endpoint.png" alt="IoT Hub - Access Policy" /></p>
<p>Next, navigate to the IoT hub's <em>Shared Access Policies</em> blade. You will need to either use one of the existing policies or add your own, and the policy you choose must have the <em>Service connect</em> permission. Click any policy to view its associated primary key.</p>
<p><img src="http://www.firewing1.com/images/2017-01-iothub-eventhub/iothub-access_policy.png" alt="IoT Hub - Access Policy" /></p>
<p>Now, we can use these four pieces of information to construct an Event Hub connection string, which follows the format <code>Endpoint=sb://EH_COMPATIBLE_ENDPOINT;EntityPath=EH_COMPATIBLE_NAME;SharedAccessKeyNa‌​me=IOTHUB_POLICY_NAME;Share‌​dAccessKey=IOTHUB_POLICY_KEY</code>.</p>
<h2>Configuring Azure Functions</h2>
<p>We will now setup an Azure Function with a trigger using the Event Hub-compatible information.</p>
<p>Open the Azure Function resource and switch to the <em>Integrate</em> tab. Add a new trigger and choose <em>Event Hub</em>, which will reveal the following settings page:</p>
<p><img src="http://www.firewing1.com/images/2017-01-iothub-eventhub/af-configure-trigger.PNG" alt="Azure Functions - Trigger configuration" /></p>
<p>Enter the Event Hub-compatible name collected from IoT Hub earlier under <em>Event Hub name</em> and then press <em>new</em> to enter the Event Hub connection string derived earlier.</p>
<p><img src="http://www.firewing1.com/images/2017-01-iothub-eventhub/af-configure-connectionstring.PNG" alt="Azure Functions - Configure connection string" /></p>
<p>Lastly, we need to add code under the <em>Develop</em> tab with a parameter that matches the <em>Event parameter name</em> field, so use the following:</p>
<pre><code>using System;
public static void Run(string myEventHubMessage, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myEventHubMessage}");
}
</code></pre><h2>Testing the connection</h2>
<p>Under the Function's <em>Develop</em> tab, click the <em>Logs</em> button from the toolbar to open the execution log. Next, send a cloud-to-device message -- if you haven't setup a device, <a href="https://github.com/Azure/azure-iot-sdk-node/blob/master/device/samples/simple_sample_device.js">simple_sample_device.js</a> from the IoT Hub Node.js SDK does nicely.</p>
<p>After sending your message, you should see that your Function triggered successfully.</p>
<h2>What about in ARM templates?</h2>
<p>This manual setup is fine for testing, but what about automation for when moving to production?</p>
<p>ARM templates provide a <code>reference()</code> function that resolves a resource's runtime state. It's perfect for obtaining the Event Hub-compatible name that was provisioned as it was created:</p>
<pre><code> ...
"parameters": {
"iotHubName": {
"defaultValue": "iothub2functions",
"type": "String"
}
},
"variables": {
"iotHubApiVersion": "2016-02-03",
"iotHubPolicyName": "service"
},
"outputs": {
"eventHubConnectionString": {
"type": "string",
"value": "[concat('Endpoint=',reference(resourceId('Microsoft.Devices/IoTHubs',parameters('iotHubName'))).eventHubEndpoints.events.endpoint,';EntityPath=',reference(resourceId('Microsoft.Devices/IoTHubs',parameters('iotHubName'))).eventHubEndpoints.events.path,';SharedAccessKeyName=',variables('iotHubPolicyName'),';SharedAccessKey=',listKeys(resourceId('Microsoft.Devices/IotHubs/Iothubkeys', parameters('iotHubName'),variables('iotHubPolicyName')), variables('iotHubApiVersion')).primaryKey)]"
}
},
...
</code></pre></div></div></div><span class="submitted-by">Posted on Tue, 2017/01/31 - 11:59pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Connecting Azure IoT Hub to Azure Functions and other Event-Hub compatible services - stewart a." addthis:url="http://www.firewing1.com/blog/2017/01/31/connecting-azure-iot-hub-azure-functions-and-other-event-hub-compatible-services"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/azure">azure</a></div><div class="field-item odd"><a href="/blog/tag/iot-hub">IoT hub</a></div><div class="field-item even"><a href="/blog/tag/functions">functions</a></div><div class="field-item odd"><a href="/blog/tag/event-hub">event hub</a></div></div></div>Wed, 01 Feb 2017 04:59:57 +0000firewing1644 at http://www.firewing1.comhttp://www.firewing1.com/blog/2017/01/31/connecting-azure-iot-hub-azure-functions-and-other-event-hub-compatible-services#commentsGetting started with the Skype for Business SDKshttp://www.firewing1.com/blog/2017/01/09/getting-started-skype-business-sdks
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>The Skype for Business App SDK and Skype Web SDK are great ways to build the unified communication experience provided by the Skype for Business (previously Lync) server directly into web and mobile applications and deliver new interactive and collaborative experiences into your application.</p>
<p>If you're getting started with the Skype SDKs and/or Office 365 for the first time, the documentation available on the The <a href="https://msdn.microsoft.com/skype/skypedeveloperplatform">Skype Developer Platform</a> is a great place to start, but there are a number of steps you'll need to work through before coding.</p>
<p>In this post, I'll detail how to get setup with Skype for Business Online (Office 365) using a developer tenant and get coding as quickly as possible. As well, this is a good time to note that that at this time, some features of the SDKs are in preview. More features are coming out with every release!</p>
<h2>Good to know: compatibility &amp; platform features</h2>
<p>As of writing (Jan. 2017), both the App SDK and Web SDK support connecting to on-premise and online (via Office 365) deployments.</p>
<p>However, at this time there are some important distinctions between the capabilities of the SDKs on the two platforms and in compatibility with O365 vs on-premise for meeting join. These differences will be rounded out in future SDK releases (for details on roadmap, see the <a href="https://www.youtube.com/watch?v=56yJg-7c2Qc">Andrew Bybee's Ignite 2016 talk</a>).</p>
<h3>App SDK</h3>
<p>The App SDK is available for iOS and Android apps, and supports the <em>unauthenticated</em> workflow. Meeting join, IM and audio-video communication is possible but done anonymously, using only a meeting link. There is no opportunity for a user to sign-in, so tasks like contact management are not available.</p>
<h3>Web SDK</h3>
<p>Contrary to the App SDK, the Web SDK has better support for <em>authenticated</em> workflows. Contact management, 1:1 conversations and more is available from the Web SDK after the user has authenticated. Anonymous meeting join, where the end-user joins a conference without signing in, is available but <strong>only</strong> when connecting to on-premise Skype for Business deployments at this time.</p>
<p>It's also important to note that both Chrome and Firefox have announced the deprecation of NPAPI plugins, which prevents the use of the Skype for Business Web App Plug-In. As such, audio-video functionality will be limited in Chrome and Firefox at this time.</p>
<p>IE11 and Safari both work with the web plug-in, and Edge supports A/V calling without any plugins via its built-in ORTC stack.</p>
<h2>Setup an Office developer tenant</h2>
<p>In order to get started, you'll need to be an administrator on Office 365 tenant and have 2-3 users that are licensed with Skype for Business. If you do not already have such an account, sign up at <a href="https://dev.office.com/devprogram">dev.office.com/devprogram</a> to obtain a free Office developer account.</p>
<p>Once your account is activated, visit <a href="https://portal.office.com">portal.office.com</a>, click the <em>Admin</em> tile, then add 2-3 users and assign them a developer license.</p>
<h2>App SDK</h2>
<p>If you intent to build a mobile app, you are now ready to go - all you need is your app and a meeting link! Check out the meeting join samples for <a href="https://github.com/OfficeDev/skype-android-app-sdk-samples">Android</a> and <a href="https://github.com/OfficeDev/skype-ios-app-sdk-samples">iOS</a>, and the <a href="https://msdn.microsoft.com/en-us/skype/appsdk/skypeappsdk">App SDK documentation</a></p>
<p>You can generate a meeting link using the Skype for Business integration with Outlook, the desktop clients or the <a href="https://sched.lync.com">Lync Web Scheduler</a>. To create them programtically, use the <a href="https://msdn.microsoft.com/en-us/skype/ucwa/unifiedcommunicationswebapi2_0">UCWA API</a>. Meeting links follow the format <code>https://meet.lync.com/tenant_name/organizer_username/meeting_id</code>.</p>
<h2>Web SDK</h2>
<p>Because the Web SDK supports authenticated workflows, it requires some additional setup in order to authenticate users against Azure AD.</p>
<h3>Creating an Azure AD Application</h3>
<p>Registering an application will allow the Web SDK to perform OAuth authentication aginst users in an Azure AD directory. Previously, managing Azure AD applications required delving into the classic portal (<a href="https://msdn.microsoft.com/en-us/skype/websdk/docs/developwebsdkappsforsfbonline">instructions here</a>) but fortunately Azure AD management is now available (in preview) in the new portal:</p>
<ol><li>Go to <a href="https://portal.azure.com">portal.azure.com</a></li>
<li>Select <em>Azure Active Directory</em> &gt; <em>App registrations</em> &gt; <em>Add</em><br /><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD.PNG" alt="Azure Portal - AAD" title="Azure Portal - AAD.PNG" /></li>
<li>
<p>Choose a human-readable name for your application and a unique sign-on URL. If unsure, use something like <code>https://tenantID.onmicrosoft.com/appname</code> - you can change it later once you move to production. Leave the type as <em>Web app / API</em>.</p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD%20-%20Create.PNG" alt="Azure Portal - AAD - Create" title="Azure Portal - AAD - Create.PNG" /></p>
</li>
<li>
<p>Select the <em>Manifest</em> button to open the manifest editor:</p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD%20-%20Manage.PNG" alt="Azure Portal - AAD - Manage" title="Azure Portal - AAD - Manage.PNG" /></p>
<p>Then set <code>oauth2AllowImplicitFlow</code> is set to <code>true</code>:</p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD%20-%20Manifest.PNG" alt="Azure Portal - AAD - Manifest" title="Azure Portal - AAD - Manifest.PNG" /></p>
</li>
<li>
<p>Next, navigate to the application's <em>Properties</em> blade and change <em>Multi-tenanted</em> to <em>Yes</em>. This will ensure that people outside of your Office tenant can use this application.</p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Portal%20-%20AAD%20-%20Multi-tenant.PNG" alt="Enabling multi-tenantancy on the application" title="Set the &#039;multi-tenanted&#039; property to &#039;Yes&#039;" /></p>
</li>
<li>
<p>Navigate to the <em>Reply URLs</em> blade and enter the URLs at which your application will be hosted. Note that while developing your application, adding <code>http://localhost</code> is convinient but be aware that it means anyone who stands up their own site on <code>http://localhost</code> and knows your client ID can authenticate against your application. Tread carefully!</p>
</li>
<li>
<p>Navigate to the <em>Required Permissions</em> blade and add <strong>delegated</strong> permissions for <em>Skype for Business Online</em>:</p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD%20-%20Permissions.PNG" alt="Azure Portal - AAD - Permissions" title="Azure Portal - AAD - Permissions.PNG" /></p>
<p><img src="http://www.firewing1.com/images/2017-01-sfb/Azure%20Portal%20-%20AAD%20-%20Permissions%202.PNG" alt="Azure Portal - AAD - Permissions 2" title="Azure Portal - AAD - Permissions 2.PNG" /></p>
</li>
</ol><p>That's it - your application is now configured. However before it can authenticate users with the Web SDK, you must consent to the application using an admin user from your Office tenant. Open a In-Private/Incognito browsing window and visit this URL, replacing both <code>CLIENT_ID</code> and <code>REDIRECT_URI</code> as configured above: <a href="https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token&amp;client_id=&lt;code&gt;CLIENT_ID&lt;/code&gt;&amp;redirect_uri=&lt;code&gt;https://REDIRECT_URI&lt;/code&gt;&amp;response_mode=form_post&amp;nonce=...&amp;resource=https://webdir.online.lync.com&amp;prompt=admin_consent">https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token&amp;client_id=<code>CLIENT_ID</code>&amp;redirect_uri=<code>https://REDIRECT_URI</code>&amp;response_mode=form_post&amp;nonce=...&amp;resource=https://webdir.online.lync.com&amp;prompt=admin_consent</a></p>
<p>Now check out the <a href="https://msdn.microsoft.com/en-us/skype/websdk/docs/skypewebsdk">Web SDK documentation</a> try running the <a href="https://github.com/OfficeDev/skype-web-sdk-samples">Web SDK samples</a>, or use the <a href="https://ucwa.skype.com/websdk">interactive Web SDK sample</a>.</p></div></div></div><span class="submitted-by">Posted on Mon, 2017/01/09 - 5:36pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Getting started with the Skype for Business SDKs - stewart a." addthis:url="http://www.firewing1.com/blog/2017/01/09/getting-started-skype-business-sdks"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/azure">azure</a></div><div class="field-item odd"><a href="/blog/tag/active-directory">active directory</a></div><div class="field-item even"><a href="/blog/tag/skype-business">skype for business</a></div><div class="field-item odd"><a href="/blog/tag/web-sdk">web sdk</a></div></div></div>Mon, 09 Jan 2017 22:36:20 +0000firewing1643 at http://www.firewing1.comhttp://www.firewing1.com/blog/2017/01/09/getting-started-skype-business-sdks#commentsChanges coming in 2017http://www.firewing1.com/blog/2016/12/26/changes-coming-2017
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>I'm writing this quick post at the end of 2016 to wish everyone happy holidays and let you know about some changes coming in 2017.</p>
<h3>Employment</h3>
<p>Earlier this year, I stopped working for my company <a href="https://diffingo.com">Diffingo Solutions Inc.</a> and am excited to say that I now work at <a href="https://www.microsoft.com">Microsoft</a>, as can be seen on my github profile (<a href="https://github.com/stewartadam">@stewartadam</a>). I think that the direction Microsoft has taken in the past two years has been very positive and I'm exicted to see what the future brings.</p>
<p>Of course, there's the mandatory note: the opinions on this blog are my own and may not represent those of my employer. However, given the technologies I interact with on a day-to-day basis, you may notice an increase in blog posts about technologies owned by my employer ;)</p>
<h3>Comments are now disabled</h3>
<p>As well, due to an influx of spam comments that are bypassing CAPTCHA and other automated anti-spam methods, I have disabled comments on my blog. I expect this will be the case for the forseeable future.</p>
<h3>New blog style coming</h3>
<p>I am likely going to convert my Drupal-based blog to one based on Markdown or other static rendering. Drupal has been great to me, but Markdown is so much easier to author in and requires 0 maintenance. As well, the rate at which I can author content has slowed so Drupal's original use case for me (maintaining Views-based lists of the various categories of howtos I was writing) no longer applies.</p></div></div></div><span class="submitted-by">Posted on Mon, 2016/12/26 - 11:30pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Changes coming in 2017 - stewart a." addthis:url="http://www.firewing1.com/blog/2016/12/26/changes-coming-2017"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div>Tue, 27 Dec 2016 04:30:52 +0000firewing1642 at http://www.firewing1.comhttp://www.firewing1.com/blog/2016/12/26/changes-coming-2017#commentsUsing OpenVPN connection to play games while abroad using Stream's In-Home Streaminghttp://www.firewing1.com/blog/2016/04/13/using-openvpn-connection-play-games-while-abroad-using-streams-home-streaming
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><h3>Introduction</h3>
<p>Steam has a great (albeit, a little glitchy) feature called In-Home Streaming that allows you to stream games from running Steam clients on your local network, effectively turning your gaming PC into a little render farm and allowing you to play from low-power devices like a laptop.</p>
<p>With the help of OpenVPN, it's possible to enable playback of games from your home PC seamlessly while away from your home network too, provided you have a decent Internet connection. This tutorial will demonstrate how to setup an OpenVPN server on Fedora 23 with a bridged network connection in let you VPN into your home network and stream Steam games from PCs on your LAN.</p>
<p>To make this work, we need to use OpenVPN in bridged mode with a <code>tap</code> network device. Bridging the ethernet and <code>tap</code> interfaces will allow VPN clients to receive an IP address on the LAN's subnet.</p>
<p>The default (and simpler) <code>tun</code> devices are not bridged, and function on a separate subnet - something which will break in-home streaming. We need to be on the same LAN so that the UDP broadcast packets sent by Steam for auto-discovery will be received by the VPN clients.</p>
<h3>Creating a network bridge</h3>
<p>Let's start by setting up the network bridge with NetworkManager and enslaving the ethernet interface. Check the name of your active network interface by running <code>nmcli d</code>, and replace the value of<code>ETH_IFACE</code> with that name below:</p>
<div class="codeblock"><code>ETH_IFACE=enp3s0<br />nmcli con add type bridge ifname br0<br />nmcli c modify bridge-br0 bridge.stp no<br />nmcli con add type bridge-slave ifname $ETH_IFACE master bridge-br0<br />nmcli c up &quot;bridge-slave-${ETH_IFACE}&quot;<br />nmcli c up bridge-br0</code></div>
<h3>Installing the OpenVPN server</h3>
<p>Next, in order to run an OpenVPN server, one needs to set up a certificate authority (CA) signs client certificates and authorizes them for login. In our case, we'll be using password authentication (for convenience) -- but OpenVPN still wants a CA setup and the server's certificate signed. Let's set up the CA for the OpenVPN server:</p>
<div class="codeblock"><code>dnf install easy-rsa<br />cp -a /usr/share/easy-rsa/3 /root/openvpn-bridged-rsa<br />cd /root/openvpn-bridged-rsa<br />./easyrsa init-pki<br />./easyrsa build-ca<br /># Enter the CA password, then accept the defaults</code></div>
<p>Now we need to create and sign the certificate for the server (set the value of <code>SERVER_ALIAS</code> to an alias of your choice):</p>
<div class="codeblock"><code>SERVER_ALIAS=homelab<br />./easyrsa gen-dh<br />./easyrsa gen-req $SERVER_ALIAS nopass<br />./easyrsa sign-req server $SERVER_ALIAS<br /># Enter &#039;yes&#039;, then CA password</code></div>
<p>Finally, we copy the keys and certificates to a dedicated folder for OpenVPN:</p>
<div class="codeblock"><code>mkdir /etc/openvpn/keys<br />chmod 700 /etc/openvpn/keys<br />cp pki/ca.crt pki/dh.pem &quot;pki/issued/${SERVER_ALIAS}.crt&quot; &quot;pki/private/${SERVER_ALIAS}.key&quot; /etc/openvpn/keys</code></div>
<p>We are now ready to configure OpenVPN. Set the variables based on your LAN's configuration (see <code>ifconfig $ETH_IFACE</code> output if unsure):</p>
<div class="codeblock"><code>BRIDGE_IP=192.168.1.1<br />NETMASK=255.255.255.0<br />IP_POOL_START=192.168.1.241<br />IP_POOL_END=192.168.1.254</p>
<p>dnf install openvpn<br />firewall-cmd --permanent --add-service openvpn<br />firewall-cmd --reload</p>
<p>cat &lt;&lt; EOF &gt; /etc/openvpn/bridged.conf<br />port 1194<br />dev tap0<br />tls-server<br />ca /etc/openvpn/keys/ca.crt<br />cert /etc/openvpn/keys/$SERVER_ALIAS.crt<br />key /etc/openvpn/keys/$SERVER_ALIAS.key # This file should be kept secret<br />dh /etc/openvpn/keys/dh.pem<br />server-bridge $BRIDGE_IP $NETMASK $IP_POOL_START $IP_POOL_END</p>
<p># Password authentication<br />client-cert-not-required<br />username-as-common-name<br />plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn</p>
<p># Allow multiple client connections from the same user<br />duplicate-cn</p>
<p># Client should attempt reconnection on link failure.<br />keepalive 10 120</p>
<p># The server doesn&#039;t need root privileges<br />user openvpn<br />group openvpn</p>
<p># Logging levels &amp; prevent repeated messages<br />verb 4<br />mute 20<br />log-append /var/log/openvpn.log<br />status /var/log/openvpn-status.log</p>
<p># Set some other options<br />comp-lzo<br />persist-key<br />persist-tun<br />push persist-key<br />push persist-tun</p>
<p># Brings up tap0 since NetworkManager won&#039;t do it automatically (yet?)<br />script-security 2<br />up up.sh<br />EOF</code></div>
<p>OpenVPN will create the <code>tap0</code> interface automatically when the OpenVPN server starts. NetworkManager is able to enslave the interface to the bridge, but won't bring <code>tap0</code> online. For that, we install a simple script:</p>
<div class="codeblock"><code>cat &lt;&lt; EOF &gt; /etc/openvpn/up.sh<br />#!/bin/bash<br />br=br0<br />dev=\$1<br />mtu=\$2<br />link_mtu=\$3<br />local_ip=\$4<br />local_netmask=\$5</p>
<p># This should be done by NetworkManager... but it can&#039;t hurt.<br />/sbin/brctl addif \$br \$dev</p>
<p># NetworkManager appears to be capable of enslaving tap0 to the bridge automatically, but won&#039;t bring up the interface.<br />/sbin/ifconfig \$dev 0.0.0.0 promisc up<br />EOF<br />chmod +x /etc/openvpn/up.sh</code></div>
<p>Next, we need to create the PAM authentication configuration file for the OpenVPN password plugin:</p>
<div class="codeblock"><code>cat &lt;&lt; EOF &gt; /etc/pam.d/openvpn<br />#%PAM-1.0<br />auth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; substack&nbsp;&nbsp;&nbsp;&nbsp; system-auth<br />auth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; postlogin<br />auth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requisite&nbsp;&nbsp;&nbsp; pam_succeed_if.so user ingroup openvpn_pw quiet<br />account&nbsp;&nbsp;&nbsp; required&nbsp;&nbsp;&nbsp;&nbsp; pam_nologin.so<br />account&nbsp;&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; system-auth<br />password&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; system-auth<br />EOF</code></div>
<p>This configuration file requires that the users logging in be a member of the <code>openvpn_pw</code> group. You can adjust the file as you see fit.</p>
<p>Finally open the OpenVPN port in the firewall and start the service:</p>
<div class="codeblock"><code>firewall-cmd --permanent --add-service openvpn<br />firewall-cmd --reload<br />systemctl enable openvpn@bridged<br />systemctl start openvpn@bridged</code></div>
<h3>Configure the firewall</h3>
<p>By default, packets are filtered through iptables which can cause issues, as packets won't freely through between the interfaces. We can disable that behavior:</p>
<div class="codeblock"><code>cat &lt;&lt; EOF &gt; /etc/modules-load.d/bridge.conf<br />br_netfilter<br />EOF</p>
<p>cat &lt;&lt; EOF &gt; /etc/sysctl.d/bridge.conf<br />net.bridge.bridge-nf-call-ip6tables=0<br />net.bridge.bridge-nf-call-iptables=0<br />net.bridge.bridge-nf-call-arptables=0<br />EOF<br />sysctl -p /etc/sysctl.d/bridge.conf</p>
<p>cat &lt;&lt; EOF &gt; /etc/udev/rules.d/99-bridge.rules<br />ACTION==&quot;add&quot;, SUBSYSTEM==&quot;module&quot;, KERNEL==&quot;br_netfilter&quot;, RUN+=&quot;/sbin/sysctl -p /etc/sysctl.d/bridge.conf&quot;<br />EOF</code></div>
<p>Note that I assume that <code>net.ipv4.ip_forward=1</code> (having libvirt seems to configure this automatically). If not, you'll want to tune the sysctl parameter <code>net.ipv4.ip_forward</code> to a value of <code>1</code>.</p>
<h3>OpenVPN client configuration</h3>
<p>That's it! Send a copy of <code>/etc/openvpn/keys/ca.crt</code> on the server to your clients, and you should now be able to connect to your OpenVPN server using this very simple client configuration (don't forget to replace <code>your.server.fqdn</code> with your server's IP address or FQDN):</p>
<div class="codeblock"><code>client<br />dev tap<br />proto udp<br />remote your.server.fqdn 1194<br />resolv-retry infinite<br />nobind<br />persist-key<br />persist-tun<br />ca ca.crt<br />auth-user-pass<br />comp-lzo<br />verb 3<br />mute 20</code></div>
<p>Once connected, you should be able to ping any machine on the LAN as well as fire up Stream for a remote gaming session.</p>
<h3>Appendix A: Steam on OS X</h3>
<p>Small note, if you're running the Steam client on OS X there's a bug where the client only sends its UDP broadcast packets for in-home streaming discovery on the machine's primary (i.e. Ethernet or Wi-FI) interface. This nifty command captures those and re-broadcasts them over the VPN's interface (once again, substitute the value of <code>BROADCAST_ADDR</code> per your LAN settings):</p>
<div class="codeblock"><code>BROADCAST_ADDR=192.168.1.255<br />sudo tshark -T fields -e data -l &#039;udp and dst port 27036&#039; | script -q /dev/null xxd -r -p | socat - UDP-DATAGRAM:${BROADCAST_ADDR}:27036,broadcast</code></div>
<p>Special thanks to Larry Land for pointing that out in his blog post <a href="http://lg.io/2015/04/12/run-your-own-high-end-cloud-gaming-service-on-ec2.html">Run your own high-end cloud gaming service on EC2</a> (which is awesome and deserves a read, by the way).</p>
<p>The above command requires the Wireshark and socat utilities to be installed, which you can grab using <a href="http://brew.sh">homebrew</a>:</p>
<div class="codeblock"><code>brew install wireshark socat</code></div>
<p>and if you don't know your subnet's broadcast address, verify it with:</p>
<div class="codeblock"><code>ifconfig tap0 | grep broadcast</code></div>
<h3>Appendix B: Troubleshooting tips</h3>
<p>Whenever possible, I like to use the most modern tooling available. This tends to bite me because documentation might not be as good or the feature set in the replacement tools might be lacking compared to the older tried and true tooling, but I try to always look forward. 'new' tooling like systemd, NetworkManager and firewalld might be rough around the edges, but I like modern feature set and consistency they bring. Most importantly, using them (instead of dropping various custom shell scripts here and there) feels a lot less like my server is held together with glue, which I like.</p>
<p>While trying different configurations, I discovered a few tricks or debugging commands that proved very useful to me - particularly while migrating commands from online resources intended for the older tooling to the tools mentioned above. Hopefully, you'll find them useful too!</p>
<h4>It's always the firewall</h4>
<p>The blame for most of the issues you will experience generally fall under firewall or routing issues.</p>
<p>First steps in testing should <i>always</i> be disabling the firewall (<code>systemctl stop firewalld</code>) and if that doesn't fix it, then move to checking the routes (<code>route -n</code> or <code>netstat -rn</code>).<br />
If you've identified the firewall is to blame, re-enable it and identifying the root cause by adjusting your configuration while listening for packets to see when packets start flowing again.</p>
<h4>Listening for packets</h4>
<p>This will be your most used tool. If things don't go as expected, listen on each of the tap0 (client), tap0 (server) and br0 (server) interfaces and then generate some traffic to see how far the packets:</p>
<div class="codeblock"><code>tcpdump -i IFNAME PATTERN</code></div>
<p>where <code>PATTERN</code> can select for hosts, ports or traffic type. In this case, a particular favorite of mine was <code>icmp or udp port 27036</code> as this let me test by trying to ping a machine on the LAN from the VPN client, as well as see if the Steam UDP traffic was making it in/out.</p>
<h4>Send UDP traffic</h4>
<p>The iperf utility can be used to test if UDP traffic makes it to the OpenVPN server (run <code>iperf -c server.ip -u -T 32 -t 3 -i 1 -p 27036</code>) from the OpenVPN clients/LAN machines (run <code>iperf -s -u -i 1 -p 27036</code>).</p>
<h4>Changing the zone of an interface</h4>
<p>firewalld has different 'zones', each with different rules (see <code>firewall-cmd --list-all-zones</code>). Interfaces will have the rules from the default zone applied to them unless otherwise configured, which you can do as follows:<br />
<div class="codeblock"><code>firewall-cmd --permanent --change-interface=IFNAME --zone=NEW_ZONE<br />firewall-cmd --reload</code></div>
<h4>Adding raw IPTables rules to firewalld</h4>
<p>e.g. to accept all packet forwarding on the bridge interface:</p>
<div class="codeblock"><code>firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i br0 -j ACCEPT</code></div>
<p>or to allow all packets flowing over br0 and tap0:</p>
<div class="codeblock"><code>firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i tap0 -j ACCEPT<br />firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i br0 -j ACCEPT</code></div>
<p>Neither of these commands should be necessary given the netfilter sysctl parameters tweaked earlier, but certain OpenVPN options (such as client2client) change the packet flow and cause packets to flow over the interface, get filters, then re-injected which could cause them to suddenly be affected by the iptables rules.</p>
<p>Recall that <code>firewall-cmd --reload</code> needs to be called before the permanent rules will take effect.</p>
<h4>Debugging IPTables</h4>
<p>The default <code>iptables -L</code> listing isn't very helpful when inserting/deleting rules by their chain offset. The following command lists all rules, numerically, and displays line numbers:</p>
<div class="codeblock"><code>iptables --line-numbers -L -n -v</code></div>
<p>You can also log dropped packets for further troubleshooting (here limited to 1/s, inserted at position 15 which was the position before the DROP rules on my machine):</p>
<div class="codeblock"><code>iptables -I INPUT 15 -j LOG -m limit --limit 60/min --log-prefix &quot;iptables dropped: &quot; --log-level 4</code></div>
<h4>Configuring a client VPN connection using only NetworkManager</h4>
<div class="codeblock"><code>VPN_IFNAME=homelab<br />nmcli c add type vpn ifname $VPN_IFNAME vpn-type openvpn<br />nmcli c modify $VPN_IFNAME<br />set vpn.data dev = tap<br />set vpn.data ca = /path/to/copy/of/ca.crt<br />set vpn.data connection-type = password<br />set vpn.data remote = your.server.fqdn<br />set vpn.data comp-lzo = yes<br />set vpn.data username = your_user<br />set vpn.data connection-type = password<br />set vpn.secrets password = your_pw</code></div>
<h4>'waiting for password' when connecting using Tunnelblock</h4>
<p>When I was attempting to test my VPN connections using Tunnelblick on OS X, I experienced an annoying bug: When trying to connect, Tunnelblick would enter a 'Waiting for password' state, but never 'get' the password nor prompt for one. Log were misleading:</p>
<div class="codeblock"><code>Tunnelblick: Obtained VPN username and password from the Keychain</code></div>
<p>No VPN password was stored in my keychain (verified using <code>Keychain Access.app</code>). Fortunately, <a href="https://community.sophos.com/products/xg-firewall/f/124/t/75819">this post</a> on the Sophos community forums correctly identified the issue as a bug after having copied/renamed a Tunnelblick connection.</p>
<p>Tunnelblick's preference file needs to be adjusted in order to correctly prompt for a password again:</p>
<div class="codeblock"><code># from https://community.sophos.com/products/xg-firewall/f/124/t/75819<br />conname=&quot;homelab&quot;<br />defaults delete net.tunnelblick.tunnelblick &quot;${conname}-keychainHasPrivateKey&quot;<br />defaults delete net.tunnelblick.tunnelblick &quot;${conname}-keychainHasUsername&quot;<br />defaults delete net.tunnelblick.tunnelblick &quot;${conname}-keychainHasUsernameAndPassword&quot;</code></div>
<h3>Additional reading</h3>
<ul>
<li>General reading about bridged networking from <a href="https://en.wikipedia.org/wiki/Bridging_(networking)">Wikipedia</a> and TLDP's <a href="http://www.tldp.org/HOWTO/text/Bridge+Firewall">Linux Bridge+Firewall Mini-HOWTO</a></li>
<li>jamielinux's excellent <a href="https://jamielinux.com/docs/libvirt-networking-handbook/bridged-network.html">libvirt networking guide</a></li>
<li>Adam Williamson's <a href="https://www.happyassassin.net/2014/07/23/bridged-networking-for-libvirt-with-networkmanager-2014-fedora-21/">blog post</a> about bridged networking (for libvirt) on Fedora 21 (similar to jamielinux's instructions, but specifically for Fedora)
<li>Discussion in Red Hat bugs <a href="https://bugzilla.redhat.com/show_bug.cgi?id=512206#c0">#512206: Disable net.bridge.bridge-nf-call-*tables by default</a> and <a href="https://bugzilla.redhat.com/show_bug.cgi?id=634736">#634736: sysctl.conf / sysctl.conf.d settings not read when modules are loaded</a></li>
<li>Larry Land's blog post <a href="http://lg.io/2015/04/12/run-your-own-high-end-cloud-gaming-service-on-ec2.html">Run your own high-end cloud gaming service on EC2</a></li>
</ul></div></div></div><span class="submitted-by">Posted on Wed, 2016/04/13 - 3:29am</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Using OpenVPN connection to play games while abroad using Stream&#039;s In-Home Streaming - stewart a." addthis:url="http://www.firewing1.com/blog/2016/04/13/using-openvpn-connection-play-games-while-abroad-using-streams-home-streaming"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/openvpn">openvpn</a></div><div class="field-item odd"><a href="/blog/tag/steam">steam</a></div><div class="field-item even"><a href="/taxonomy/term/196">gaming</a></div><div class="field-item odd"><a href="/blog/tag/streaming">streaming</a></div><div class="field-item even"><a href="/taxonomy/term/42">fedora</a></div></div></div>Wed, 13 Apr 2016 07:29:44 +0000firewing1640 at http://www.firewing1.comhttp://www.firewing1.com/blog/2016/04/13/using-openvpn-connection-play-games-while-abroad-using-streams-home-streaming#commentsMigrating a live server to another host with no downtimehttp://www.firewing1.com/blog/2015/03/05/migrating-live-server-another-host-no-downtime
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>I have had a 1U server co-located for some time now at iWeb Technologies' datacenter in Montreal. So far I've had no issues and it did a wonderful job hosting websites &amp; a few other VMs, but because of my concern for its aging hardware I wanted to migrate away before disaster struck.</p>
<p>Modern VPS offerings are a steal in terms of they performance they offer for the price, and Linode's 4096 plan caught my eye at a nice sweet spot. Backed by powerful CPUs and SSD storage, their VPS is blazingly fast and the only downside is I would lose some RAM and HDD-backed storage compared to my 1U server. The bandwidth provided wit the Linode was also a nice bump up from my previous 10Mbps, 500GB/mo traffic limit.</p>
<p>When CentOS 7 was released I took the opportunity to immediately start modernizing my CentOS 5 configuration and test its configuration. I wanted to ensure <strong>full continuity</strong> for client-facing services - other than a nice speed boost, I wanted clients to take no manual action on their end to reconfigure their devices or domains.</p>
<p>I also wanted to ensure <strong>zero downtime</strong>. As the DNS A records are being migrated, I didn't want emails coming in to the wrong server (or clients checking a stale inboxes until they started seeing the new mailserver IP). I can easily configure Postfix to relay all incoming mail on the CentOS 5 server to the IP of the CentOS 7 one to avoid any loss of emails, but there's still the issue that some end users might connect to the old server and get served their old IMAP inbox for some time.</p>
<p>So first things first, after developing a prototype VM that offered the same service set I went about buying a small Linode for a month to test the configuration some of my existing user data from my CentOS 5 server. MySQL was sufficiently easy to migrate over and Dovecot was able to preserve all UUIDs, so my inbox continued to sync seamlessly. Apache complained a bit when importing my virtual host configurations due to the new 2.4 syntax, but nothing a few sed commands couldn't fix. So with full continuity out of the way, I had to develop a strategy to handle zero downtime.</p>
<p>With some foresight and DNS TTL adjustments, we can get <em>near</em> zero downtime assuming all resolvers comply with your TTL. Simply set your TTL to 300 (5 minutes) a day or so before the migration occurs and as your old TTL expires, resolvers will see the new TTL and will not cache the IP for as long. Even with a short TTL, that's still up to 5 minutes of downtime and clients often do bad things... The IP might still be cached (e.g. at the ISP, router, OS, or browser) for longer. Ultimately, I'm the one that ends up looking bad in that scenario even though I have done what I can on the server side and have no ability to fix the broken clients.</p>
<p>To work around this, I discovered an incredibly handy tool <code>socat</code> that can make magic happen. <code>socat</code> routes data between sockets, network connections, files, pipes, you name it. Installing it is as easy as:
<code>yum install socat</code></p>
<p>A quick script later and we can forward all connections from the old host to the new host:</p>
<div class="codeblock"><code>#!/bin/sh<br />NEWIP=0.0.0.0<br /><br /># Stop services on this host<br />for SERVICE in dovecot postfix httpd mysqld;do<br /> /sbin/service $SERVICE stop<br />done<br /><br /># Some cleanup<br />rm /var/lib/mysql/mysql.sock<br /><br /># Map the new server's MySQL to localhost:3307<br /># Assumes capability for password-less (e.g. pubkey) login<br />ssh $NEWIP -L 3307:localhost:3306 &amp;<br />socat unix-listen:/var/lib/mysql/mysql.sock,fork,reuseaddr,unlink-early,unlink-close,user=mysql,group=mysql,mode=777 TCP:localhost:3307 &amp;<br /><br /># Map ports from each service to the new host<br />for PORT in 110 995 143 993 25 465 587 80 3306;do<br /> echo "Starting socat on port $PORT..."<br /> socat TCP-LISTEN:$PORT,fork TCP:${NEWIP}:${PORT} &amp;<br /> sleep 1<br />done</code></div>
<p>And just like that, every connection made to the old server is immediately forwarded to the new one. This includes the MySQL socket (which is automatically used instead of a TCP connection a host of 'localhost' is passed to MySQL).</p>
<p>Note how we establish a SSH tunnel mapping a connection to localhost:3306 on the new server to port 3307 on the old one instead of simply forwarding the connection and socket to the new server - this is done so that if you have users who are permitted on 'localhost' only, they can still connect (forwarding the connection will deny access due to a connection from a unauthorized remote host).</p>
<p><strong>Update:</strong> a friend has pointed out this video to me, if you thought 0 downtime was bad enough... These guys move a live server 7km through public transport without losing power or network!</p>
<iframe width="640" height="480" src="https://www.youtube.com/embed/vQ5MA685ApE?cc_load_policy=1" frameborder="0" allowfullscreen=""></iframe></div></div></div><span class="submitted-by">Posted on Thu, 2015/03/05 - 8:37pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Migrating a live server to another host with no downtime - stewart a." addthis:url="http://www.firewing1.com/blog/2015/03/05/migrating-live-server-another-host-no-downtime"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/taxonomy/term/144">CentOS</a></div><div class="field-item odd"><a href="/taxonomy/term/43">linux</a></div><div class="field-item even"><a href="/taxonomy/term/38">server</a></div></div></div>Fri, 06 Mar 2015 01:37:05 +0000firewing1639 at http://www.firewing1.comhttp://www.firewing1.com/blog/2015/03/05/migrating-live-server-another-host-no-downtime#commentsAlex Williamson's talk at KVM Forum 2014http://www.firewing1.com/blog/2014/12/06/alex-williamsons-talk-kvm-forum-2014
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even">Alex gave a very interesting talk at KVM Forum 2014 about the current state of VGA passthrough using KVM &amp; VFIO:
<iframe width="560" height="315" src="//www.youtube.com/embed/NhZ9eIpg2nM" frameborder="0" allowfullscreen=""></iframe>
<br />
Also, I think nVidia is making an incredibly silly choice (apparently accidentally) causing Code 43 in their drivers when virtualization is detected and refusing to fix the bugs. Virtualization is becoming evermore powerful and this is just going to push potential customers away to AMD. Once they establish a reputation for their cards not working well with virtualization, they're going to have trouble gaining custom confidence even if they reverse their stance on not fixing the Code 43 bugs.</div></div></div><span class="submitted-by">Posted on Sat, 2014/12/06 - 2:36pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Alex Williamson&#039;s talk at KVM Forum 2014 - stewart a." addthis:url="http://www.firewing1.com/blog/2014/12/06/alex-williamsons-talk-kvm-forum-2014"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/blog/tag/virt">virt</a></div></div></div>Sat, 06 Dec 2014 19:36:53 +0000firewing1637 at http://www.firewing1.comhttp://www.firewing1.com/blog/2014/12/06/alex-williamsons-talk-kvm-forum-2014#commentsSharing your Cyberduck bookmarks between computers via coud sync (Dropbox, Google Drive or Copy)http://www.firewing1.com/blog/2014/05/05/sharing-your-cyberduck-bookmarks-between-computers-coud-sync-dropbox-google-drive-or
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Cyberduck <a href="https://trac.cyberduck.io/wiki/help/en/howto/bookmarks?action=diff&amp;version=60&amp;old_version=59">recently removed</a> a particularly useful piece of information from their wiki regarding the sharing of bookmarks because it is no longer compatible with the sandboxed variant of Cyberduck available from the App Store. It is, however, still compatible with the Windows and OS X download available directly from its website.</p>
<p>To setup bookmark sharing between Cyberduck clients (works with both OS X or Windows), simply create a folder in your cloud sync folder and then point Cyberduck to it.</p>
<p>On OS X, open a Terminal and execute:</p>
<div class="codeblock"><code>defaults write ch.sudo.cyberduck application.support.path ~/Dropbox/Cyberduck</code></div>
<p>On Windows, press Super+R (Super is the key with the Windows logo on it) to open the "Run" dialog, and enter <code>%APPDATA%</code>. Next, open the <code>Cyberduck.exe_Url_[some_garble]\[Version]\user.config</code> file and modify the config file to add the new parameter:</p>
<div class="codeblock"><code>&lt;setting name=&quot;CdSettings&quot; serializeAs=&quot;Xml&quot;&gt;<br />&nbsp; &lt;value&gt;<br />&nbsp;&nbsp;&nbsp; &lt;settings&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;setting name=&quot;application.support.path&quot; value=&quot;C:\Users\yourname\Dropbox\Cyberduck&quot; /&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/settings&gt;<br />&nbsp; &lt;/value&gt;<br />&lt;/setting&gt;</code></div></div></div></div><span class="submitted-by">Posted on Mon, 2014/05/05 - 9:41pm</span><div class="field field-name-field-share field-type-addthis field-label-hidden"><div class="field-items"><div class="field-item even"><div class="addthis_toolbox addthis_default_style " addthis:title="Sharing your Cyberduck bookmarks between computers via coud sync (Dropbox, Google Drive or Copy) - stewart a." addthis:url="http://www.firewing1.com/blog/2014/05/05/sharing-your-cyberduck-bookmarks-between-computers-coud-sync-dropbox-google-drive-or"><a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_email"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_facebook"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_twitter"></a>
<a href="http://www.addthis.com/bookmark.php?v=250" class="addthis_button_google_plusone_share"></a>
</div>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"><div class="field-label">Tags:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/taxonomy/term/177">sync</a></div><div class="field-item odd"><a href="/taxonomy/term/104">cross-platform</a></div></div></div>Tue, 06 May 2014 01:41:38 +0000firewing1635 at http://www.firewing1.comhttp://www.firewing1.com/blog/2014/05/05/sharing-your-cyberduck-bookmarks-between-computers-coud-sync-dropbox-google-drive-or#comments