397 lines
22 KiB
HTML
397 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
|
|
|
|
<html class="no-js" lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>How to send raw network packets in Python with tun/tap</title>
|
|
<meta name="author" content="Julia Evans">
|
|
<meta name="HandheldFriendly" content="True">
|
|
<meta name="MobileOptimized" content="320">
|
|
<meta name="description" content="How to send raw network packets in Python with tun/tap">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
<meta property="og:title" content='How to send raw network packets in Python with tun/tap'>
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:url" content="https://jvns.ca/blog/2022/09/06/send-network-packets-python-tun-tap/" />
|
|
<meta property="og:site_name" content="Julia Evans" />
|
|
|
|
<link rel="canonical" href="https://jvns.ca/blog/2022/09/06/send-network-packets-python-tun-tap/">
|
|
<link href="/favicon.ico" rel="icon">
|
|
|
|
<link href="/stylesheets/screen.css" rel="preload" type="text/css" as="style">
|
|
|
|
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
|
|
<link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css">
|
|
|
|
|
|
<link href="/atom.xml" rel="alternate" title="Julia Evans" type="application/atom+xml">
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">
|
|
<script defer data-domain="jvns.ca" src="https://plausible.io/js/script.js"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js" integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
|
|
|
|
<script defer type="text/javascript">
|
|
window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=document.createElement("script");r.type="text/javascript",r.async=!0,r.src="https://cdn.heapanalytics.com/js/heap-"+e+".js";var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(r,a);for(var n=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","resetIdentity","removeEventProperty","setEventProperties","track","unsetEventProperty"],o=0;o<p.length;o++)heap[p[o]]=n(p[o])};
|
|
heap.load("2242143965");
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="skiptocontent">
|
|
<a href="#main">Skip to main content</a>
|
|
</div>
|
|
<div id="wrap">
|
|
<header role="banner">
|
|
<hgroup>
|
|
<h1><a href="/">Julia Evans</a></h1>
|
|
</hgroup>
|
|
<ul class="header-links">
|
|
<li><a href="/about">About</a></li>
|
|
<li><a href="/talks">Talks</a></li>
|
|
<li><a href="/projects/">Projects</a></li>
|
|
<li><a rel="me" href="https://social.jvns.ca/@b0rk">Mastodon</a></li>
|
|
<li><a href="https://bsky.app/profile/b0rk.jvns.ca">Bluesky</a></li>
|
|
<li><a href="https://github.com/jvns">Github</a></li>
|
|
</ul>
|
|
</header>
|
|
<nav role="navigation" class="header-nav"><ul class="main-navigation">
|
|
<li><a href="/categories/favorite/">Favorites</a></li>
|
|
<li><a href="/til/">TIL</a></li>
|
|
<li><a href="https://wizardzines.com">Zines</a></li>
|
|
<li class="subscription" data-subscription="rss"><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
|
|
</ul>
|
|
</nav>
|
|
<div id="main">
|
|
<div id="content">
|
|
|
|
|
|
<div>
|
|
<article class="hentry" role="article">
|
|
<header>
|
|
<h1 class="entry-title">How to send raw network packets in Python with tun/tap</h1>
|
|
|
|
<div class="post-tags">
|
|
|
|
</div>
|
|
<p class="meta sans">
|
|
<time class="date" datetime="2022-09-06T11:43:14" pubdate data-updated="true">
|
|
|
|
September 6, 2022
|
|
|
|
</time>
|
|
</p>
|
|
</header>
|
|
<main>
|
|
<p>Hello!</p>
|
|
<p>Recently I’ve been working on a project where I implement a bunch of tiny toy
|
|
working versions of computer networking protocols in Python without using any
|
|
libraries, as a way to explain how computer networking works.</p>
|
|
<p>I’m still working on writing up that project, but today I wanted to talk about
|
|
how to do the very first step: sending network packets in Python.</p>
|
|
<p>In this post we’re going to send a SYN packet (the first packet in a TCP
|
|
connection) from a tiny Python program, and get a reply from <code>example.com</code>. All the code from this post is in <a href="https://gist.github.com/jvns/552e6d5e6fec6c3ddf2fcd4ccdab45d5">this gist</a>.</p>
|
|
<h3 id="what-s-a-network-packet" class="post-heading">
|
|
<a href="#what-s-a-network-packet">
|
|
what’s a network packet?
|
|
</a>
|
|
</h3>
|
|
<p>A network packet is a byte string. For example, here’s the first packet in a TCP connection:</p>
|
|
<pre><code>b'E\x00\x00,\x00\x01\x00\x00@\x06\x00\xc4\xc0\x00\x02\x02"\xc2\x95Cx\x0c\x00P\xf4p\x98\x8b\x00\x00\x00\x00`\x02\xff\xff\x18\xc6\x00\x00\x02\x04\x05\xb4'
|
|
</code></pre>
|
|
<p>I’m not going to talk about the structure of this byte string in this post
|
|
(though I’ll say that this particular byte string has two parts: the first 20
|
|
bytes are the IP address part and the rest is the TCP part)</p>
|
|
<p>The point is that to send network packets, we need to be able to send and
|
|
receive strings of bytes.</p>
|
|
<h3 id="why-tun-tap" class="post-heading">
|
|
<a href="#why-tun-tap">
|
|
why tun/tap?
|
|
</a>
|
|
</h3>
|
|
<p>The problem with writing your own TCP implementation on Linux (or any operating
|
|
system) is – the Linux kernel already has a TCP implementation!</p>
|
|
<p>So if you send out a SYN packet on your normal network interface to a host like
|
|
example.com, here’s what will happen:</p>
|
|
<ol>
|
|
<li>you send a SYN packet to example.com</li>
|
|
<li>example.com replies with a SYN ACK (so far so good!)</li>
|
|
<li>the Linux kernel on your machine gets the SYN ACK, thinks “wtf?? I didn’t make this connection??”, and closes the connection</li>
|
|
<li>you’re sad. no TCP connection for you.</li>
|
|
</ol>
|
|
<p>I was talking to a friend about this problem a few years ago and he said “you
|
|
should use tun/tap!”. It took quite a few hours to figure out how to do that
|
|
though, which is why I’m writing this blog post :)</p>
|
|
<h3 id="tun-tap-gives-you-a-virtual-network-device" class="post-heading">
|
|
<a href="#tun-tap-gives-you-a-virtual-network-device">
|
|
tun/tap gives you a “virtual network device”
|
|
</a>
|
|
</h3>
|
|
<p>The way I like to think of <code>tun/tap</code> is – imagine I have a tiny computer in my
|
|
network which is sending and receiving network packets. But instead of it being
|
|
a real computer, it’s just a Python program I wrote.</p>
|
|
<p>That explanation is honestly worse than I would like. I wish I understood
|
|
exactly how tun/tap devices interfaced with the real Linux network stack but
|
|
unfortunately I do not, so “virtual network device” is what you’re getting.
|
|
Hopefully the code examples below will make all it a bit more clear.</p>
|
|
<h3 id="tun-vs-tap" class="post-heading">
|
|
<a href="#tun-vs-tap">
|
|
tun vs tap
|
|
</a>
|
|
</h3>
|
|
<p>The system called “tun/tap” lets you create two kinds of network interfaces:</p>
|
|
<ul>
|
|
<li>“tun”, which lets you set IP-layer packets</li>
|
|
<li>“tap”, which lets you set Ethernet-layer packets</li>
|
|
</ul>
|
|
<p>We’re going to be using <strong>tun</strong>, because that’s what I could figure out how to
|
|
get to work. It’s possible that tap would work too.</p>
|
|
<h3 id="how-to-create-a-tun-interface" class="post-heading">
|
|
<a href="#how-to-create-a-tun-interface">
|
|
how to create a tun interface
|
|
</a>
|
|
</h3>
|
|
<p>Here’s how I created a tun interface with IP address 192.0.2.2.</p>
|
|
<pre><code>sudo ip tuntap add name tun0 mode tun user $USER
|
|
sudo ip link set tun0 up
|
|
sudo ip addr add 192.0.2.1 peer 192.0.2.2 dev tun0
|
|
|
|
sudo iptables -t nat -A POSTROUTING -s 192.0.2.2 -j MASQUERADE
|
|
sudo iptables -A FORWARD -i tun0 -s 192.0.2.2 -j ACCEPT
|
|
sudo iptables -A FORWARD -o tun0 -d 192.0.2.2 -j ACCEPT
|
|
</code></pre>
|
|
<p>These commands do two things:</p>
|
|
<ol>
|
|
<li>Create the <code>tun</code> device with the IP <code>192.0.2.2</code> (and give your user access to write to it)</li>
|
|
<li>set up <code>iptables</code> to proxy packets from that tun device to the internet using NAT</li>
|
|
</ol>
|
|
<p>The iptables part is very important because otherwise the packets would only
|
|
exist inside my computer and wouldn’t be sent to the internet, and what fun
|
|
would that be?</p>
|
|
<p>I’m not going to explain this <code>ip addr add</code> command because I don’t understand
|
|
it, I find <code>ip</code> to be very inscrutable and for now I’m resigned to just copying
|
|
and pasting <code>ip</code> commands without fully understanding them. It does work
|
|
though.</p>
|
|
<h3 id="how-to-connect-to-the-tun-interface-in-python" class="post-heading">
|
|
<a href="#how-to-connect-to-the-tun-interface-in-python">
|
|
how to connect to the tun interface in Python
|
|
</a>
|
|
</h3>
|
|
<p>Here’s a function to open a tun interface, you call it like <code>openTun('tun0')</code>.
|
|
I figured out how to write it by searching through the
|
|
<a href="https://scapy.net/">scapy</a> source code for “tun”.</p>
|
|
<pre><code>import struct
|
|
from fcntl import ioctl
|
|
|
|
def openTun(tunName):
|
|
tun = open("/dev/net/tun", "r+b", buffering=0)
|
|
LINUX_IFF_TUN = 0x0001
|
|
LINUX_IFF_NO_PI = 0x1000
|
|
LINUX_TUNSETIFF = 0x400454CA
|
|
flags = LINUX_IFF_TUN | LINUX_IFF_NO_PI
|
|
ifs = struct.pack("16sH22s", tunName, flags, b"")
|
|
ioctl(tun, LINUX_TUNSETIFF, ifs)
|
|
return tun
|
|
</code></pre>
|
|
<p>All this is doing is</p>
|
|
<ol>
|
|
<li>opening <code>/dev/net/tun</code> in binary mode</li>
|
|
<li>calling an <code>ioctl</code> to tell Linux that we want a <code>tun</code> device, and that the one we want is called <code>tun0</code> (or whatever <code>tunName</code> we’ve passed to the function).</li>
|
|
</ol>
|
|
<p>Once it’s open, we can <code>read</code> from and <code>write</code> to it like any other file in Python.</p>
|
|
<h3 id="let-s-send-a-syn-packet" class="post-heading">
|
|
<a href="#let-s-send-a-syn-packet">
|
|
let’s send a SYN packet!
|
|
</a>
|
|
</h3>
|
|
<p>Now that we have the <code>openTun</code> function, we can send a SYN packet!</p>
|
|
<p>Here’s what the Python code looks like, using the <code>openTun</code> function.</p>
|
|
<pre><code>syn = b'E\x00\x00,\x00\x01\x00\x00@\x06\x00\xc4\xc0\x00\x02\x02"\xc2\x95Cx\x0c\x00P\xf4p\x98\x8b\x00\x00\x00\x00`\x02\xff\xff\x18\xc6\x00\x00\x02\x04\x05\xb4'
|
|
tun = openTun(b"tun0")
|
|
tun.write(syn)
|
|
reply = tun.read(1024)
|
|
print(repr(reply))
|
|
</code></pre>
|
|
<p>If I run this as <code>sudo python3 syn.py</code>, it prints out the reply from <code>example.com</code>:</p>
|
|
<pre><code>b'E\x00\x00,\x00\x00@\x00&\x06\xda\xc4"\xc2\x95C\xc0\x00\x02\x02\x00Px\x0cyvL\x84\xf4p\x98\x8c`\x12\xfb\xe0W\xb5\x00\x00\x02\x04\x04\xd8'
|
|
</code></pre>
|
|
<p>Obviously this is a pretty silly way to send a SYN packet – a real
|
|
implementation would have actual code to generate that byte string instead of
|
|
hardcoding it, and we would parse the reply instead of just printing out the
|
|
raw byte string. But I didn’t want to go into the structure of TCP in this post
|
|
so that’s what we’re doing.</p>
|
|
<h3 id="looking-at-these-packets-with-tcpdump" class="post-heading">
|
|
<a href="#looking-at-these-packets-with-tcpdump">
|
|
looking at these packets with tcpdump
|
|
</a>
|
|
</h3>
|
|
<p>If we run tcpdump on the <code>tun0</code> interface, we can see the packet we sent and the answer from <code>example.com</code>:</p>
|
|
<pre><code>$ sudo tcpdump -ni tun0
|
|
12:51:01.905933 IP 192.0.2.2.30732 > 34.194.149.67.80: Flags [S], seq 4101019787, win 65535, options [mss 1460], length 0
|
|
12:51:01.932178 IP 34.194.149.67.80 > 192.0.2.2.30732: Flags [S.], seq 3300937416, ack 4101019788, win 64480, options [mss 1240], length 0
|
|
</code></pre>
|
|
<p><code>Flags [S]</code> is the SYN we sent, and <code>Flags [S.]</code> is the SYN ACK packet in
|
|
response! We successfully communicated! And the Linux network stack didn’t
|
|
interfere at all!</p>
|
|
<h3 id="tcpdump-also-shows-us-how-nat-is-working" class="post-heading">
|
|
<a href="#tcpdump-also-shows-us-how-nat-is-working">
|
|
tcpdump also shows us how NAT is working
|
|
</a>
|
|
</h3>
|
|
<p>We can also run <code>tcpdump</code> on my real network interface (<code>wlp3so</code>, my wireless card), to see the packets being sent and received. We’ll pass <code>-i wlp3s0</code> instead of <code>-i tun0</code>.</p>
|
|
<pre><code>$ sudo tcpdump -ni wlp3s0 host 34.194.149.67
|
|
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
|
|
listening on wlp3s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
|
|
12:56:01.204382 IP 192.168.1.181.30732 > 34.194.149.67.80: Flags [S], seq 4101019787, win 65535, options [mss 1460], length 0
|
|
12:56:01.228239 IP 34.194.149.67.80 > 192.168.1.181.30732: Flags [S.], seq 144769955, ack 4101019788, win 64480, options [mss 1240], length 0
|
|
12:56:05.334427 IP 34.194.149.67.80 > 192.168.1.181.30732: Flags [S.], seq 144769955, ack 4101019788, win 64480, options [mss 1240], length 0
|
|
12:56:13.524973 IP 34.194.149.67.80 > 192.168.1.181.30732: Flags [S.], seq 144769955, ack 4101019788, win 64480, options [mss 1240], length 0
|
|
12:56:29.705007 IP 34.194.149.67.80 > 192.168.1.181.30732: Flags [S.], seq 144769955, ack 4101019788, win 64480, options [mss 1240], length 0
|
|
</code></pre>
|
|
<p>A couple of things to notice here:</p>
|
|
<ul>
|
|
<li>The IP addresses are different – that IPtables rule from above has rewritten them from <code>192.0.2.2</code> to <code>192.168.1.181</code>. This rewriting is called “network address translation”, or “NAT”.</li>
|
|
<li>We’re getting a bunch of replies from <code>example.com</code> – it’s doing an
|
|
exponential backoff where it retries after 4 seconds, then 8 seconds, then 16
|
|
seconds. This is because we didn’t finish the TCP handshake – we just sent a
|
|
SYN and left it hanging! There’s actually a type of DDOS attack like this
|
|
called SYN flooding, but just sending one or two SYN packets isn’t a big
|
|
deal.</li>
|
|
<li>I had to add <code>host 34.194.149.67</code> because there are a lot of TCP packets being sent on my real wifi connection so I needed to ignore those</li>
|
|
</ul>
|
|
<p>I’m not totally sure why we see more SYN replies on <code>wlp3s0</code> than on <code>tun0</code>, my
|
|
guess is that it’s because we only read 1 reply in our Python program.</p>
|
|
<h3 id="this-is-pretty-easy-and-really-reliable" class="post-heading">
|
|
<a href="#this-is-pretty-easy-and-really-reliable">
|
|
this is pretty easy and really reliable
|
|
</a>
|
|
</h3>
|
|
<p>The last time I tried to implement TCP in Python I did it with something called
|
|
“ARP spoofing”. I won’t talk about that here (there are some posts about it on
|
|
this blog back in 2013), but this way is a lot more reliable.</p>
|
|
<p>And ARP spoofing is kind of a sketchy thing to do on a network you don’t own.</p>
|
|
<h3 id="here-s-the-code" class="post-heading">
|
|
<a href="#here-s-the-code">
|
|
here’s the code
|
|
</a>
|
|
</h3>
|
|
<p>I put all the code from this blog post in <a href="https://gist.github.com/jvns/552e6d5e6fec6c3ddf2fcd4ccdab45d5">this gist</a>, if you want to try it yourself, you can run</p>
|
|
<pre><code>bash setup.sh # needs to run as root, has lots of `sudo` commands
|
|
python3 syn.py # runs as a regular user
|
|
</code></pre>
|
|
<p>It only works on Linux, but I think there’s a way to set up tun/tap on Mac too.</p>
|
|
<h3 id="a-plug-for-scapy" class="post-heading">
|
|
<a href="#a-plug-for-scapy">
|
|
a plug for scapy
|
|
</a>
|
|
</h3>
|
|
<p>I’ll close with a plug for <a href="https://scapy.net/">scapy</a> here: it’s a really
|
|
great Python networking library for doing this kind of experimentation without
|
|
writing all the code yourself.</p>
|
|
<p>This post is about writing all the code yourself though so I won’t say more
|
|
about it than that.</p>
|
|
|
|
</main>
|
|
|
|
<footer>
|
|
|
|
<style type="text/css">
|
|
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; display: inline;}
|
|
#mc_embed_signup {
|
|
display: inline;
|
|
}
|
|
#mc_embed_signup input.button {
|
|
background: #ff5e00;
|
|
display: inline;
|
|
color: white;
|
|
padding: 6px 12px;
|
|
}
|
|
</style>
|
|
<div class="sharing">
|
|
|
|
<style>
|
|
.form-inline {
|
|
display:flex; flex-flow: row wrap; justify-content: center;
|
|
}
|
|
.form-inline input, .form-inline span {
|
|
padding: 10px;
|
|
}
|
|
.form-inline input {
|
|
display:inline;
|
|
max-width:30%;
|
|
margin: 0 10px 0 0;
|
|
background-color: #fff;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
padding: 10px;
|
|
}
|
|
button {
|
|
background-color: #f50;
|
|
box-shadow: none;
|
|
border: 0;
|
|
border-radius: 5px;
|
|
color: white;
|
|
padding: 5px 10px;
|
|
}
|
|
@media (max-width: 800px) {
|
|
.form-inline input {
|
|
margin: 10px 0;
|
|
max-width:100% !important;
|
|
}
|
|
.form-inline {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div align="center">
|
|
<form class="form-inline" action="https://app.convertkit.com/forms/1052396/subscriptions" method="post" data-uid="8884355abb" data-format="inline" data-version="5">
|
|
<span> Want a weekly digest of this blog?</span>
|
|
<input name="email_address" type="text" placeholder="Email address" />
|
|
<button type="submit" data-element="submit">Subscribe</button>
|
|
</form>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
<p class="meta">
|
|
|
|
<a class="basic-alignment left" href="https://jvns.ca/blog/2022/08/30/a-way-to-categorize-debugging-skills/" title="Previous Post: Some ways to get better at debugging">Some ways to get better at debugging</a>
|
|
|
|
|
|
<a class="basic-alignment right" href="https://jvns.ca/blog/2022/09/12/why-do-domain-names-end-with-a-dot-/" title="Next Post: Why do domain names sometimes end with a dot?">Why do domain names sometimes end with a dot?</a>
|
|
|
|
</p>
|
|
</footer>
|
|
|
|
</article>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<nav role="navigation" class="footer-nav"> <a href="/">Archives</a>
|
|
</nav>
|
|
<footer role="contentinfo"><span class="credit">© Julia Evans. </span>
|
|
<span>If you like this, you may like <a href="https://web.archive.org/web/20181228051203/http://www.uliaea.ca/">Ulia Ea</a> or, more seriously, this list of <a href="https://jvns.ca/blogroll">blogs I love</a> or some <a href="https://jvns.ca/bookshelf">books I've read</a>. <br>
|
|
<p class="rc-scout__text"><i class="rc-scout__logo"></i>
|
|
You might also like the <a class="rc-scout__link" href="https://www.recurse.com/scout/click?t=546ea46360584b522270b8c3e5d830f8">Recurse Center</a>, my very favorite programming community <a href="/categories/hackerschool/">(my posts about it)</a></p>
|
|
</span>
|
|
<style class="rc-scout__style" type="text/css">.rc-scout{display:block;padding:0;border:0;margin:0;}.rc-scout__text{display:block;padding:0;border:0;margin:0;height:100%;font-size:100%;}.rc-scout__logo{display:inline-block;padding:0;border:0;margin:0;width:0.85em;height:0.85em;background:no-repeat center url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2012%2015%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%2212%22%20height%3D%2210%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%221%22%20y%3D%221%22%20width%3D%2210%22%20height%3D%228%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%228%22%20height%3D%226%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%2361ae24%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%2361ae24%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%2361ae24%22%3E%3C%2Frect%3E%3Crect%20x%3D%223%22%20y%3D%225%22%20width%3D%222%22%20height%3D%221%22%20fill%3D%22%2361ae24%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%225%22%20width%3D%222%22%20height%3D%221%22%20fill%3D%22%2361ae24%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%229%22%20width%3D%224%22%20height%3D%223%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%221%22%20y%3D%2211%22%20width%3D%2210%22%20height%3D%224%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%220%22%20y%3D%2212%22%20width%3D%2212%22%20height%3D%223%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%223%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%225%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%227%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%228%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%229%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3C%2Fsvg%3E');}.rc-scout__link:link,.rc-scout__link:visited{color:#61ae24;text-decoration:underline;}.rc-scout__link:hover,.rc-scout__link:active{color:#4e8b1d;}</style>
|
|
</footer>
|
|
<script type="text/rocketscript">
|
|
(function(){
|
|
var twitterWidgets = document.createElement('script');
|
|
twitterWidgets.type = 'text/javascript';
|
|
twitterWidgets.async = true;
|
|
twitterWidgets.src = 'http://platform.twitter.com/widgets.js';
|
|
document.getElementsByTagName('head')[0].appendChild(twitterWidgets);
|
|
})();
|
|
</script>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
|