mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-11-03 04:17:17 -05:00
496 lines
22 KiB
HTML
496 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<link rel="shortcut icon" href="../img/favicon.ico">
|
|
<title>Authentication - Icecast Docs</title>
|
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
|
|
|
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
|
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
|
<link rel="stylesheet" href="../css/highlight.css">
|
|
|
|
<script>
|
|
// Current page data
|
|
var mkdocs_page_name = "Authentication";
|
|
var mkdocs_page_input_path = "auth.md";
|
|
var mkdocs_page_url = "/auth/";
|
|
</script>
|
|
|
|
<script src="../js/jquery-2.1.1.min.js"></script>
|
|
<script src="../js/modernizr-2.8.3.min.js"></script>
|
|
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
|
|
|
</head>
|
|
|
|
<body class="wy-body-for-nav" role="document">
|
|
|
|
<div class="wy-grid-for-nav">
|
|
|
|
|
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
|
<div class="wy-side-nav-search">
|
|
<a href=".." class="icon icon-home"> Icecast Docs</a>
|
|
|
|
</div>
|
|
|
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
|
<ul class="current">
|
|
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="..">Introduction</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../basic_setup/">Basic Setup</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../config_file/">Configuration File</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../server_stats/">Server Statistics</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1 current">
|
|
|
|
<a class="current" href="./">Authentication</a>
|
|
<ul class="subnav">
|
|
|
|
<li class="toctree-l2"><a href="#listener-authentication">Listener Authentication</a></li>
|
|
|
|
|
|
<li class="toctree-l2"><a href="#htpasswd-listener-authentication">htpasswd Listener Authentication</a></li>
|
|
|
|
<ul>
|
|
|
|
<li><a class="toctree-l3" href="#configuring-users-and-passwords">Configuring Users and Passwords</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#finishing-it-all-off">Finishing it all off</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
<li class="toctree-l2"><a href="#url">URL</a></li>
|
|
|
|
<ul>
|
|
|
|
<li><a class="toctree-l3" href="#mount_add">mount_add</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#mount_remove">mount_remove</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#listener_add">listener_add</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#listener_remove">listener_remove</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#stream_auth">stream_auth</a></li>
|
|
|
|
<li><a class="toctree-l3" href="#other-options">Other Options</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
<li class="toctree-l2"><a href="#a-note-about-players-and-authentication">A note about players and authentication</a></li>
|
|
|
|
|
|
<li class="toctree-l2"><a href="#source-authentication">Source Authentication</a></li>
|
|
|
|
<ul>
|
|
|
|
<li><a class="toctree-l3" href="#url-authentication-stream_auth">URL authentication: stream_auth</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../relaying/">Relaying</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../yp/">Listing in a YellowPage Directory</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../admin_interface/">Admin Interface</a>
|
|
</li>
|
|
|
|
<li class="toctree-l1">
|
|
|
|
<a class="" href="../win32/">Windows Specific</a>
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
|
|
|
|
|
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
|
<a href="..">Icecast Docs</a>
|
|
</nav>
|
|
|
|
|
|
<div class="wy-nav-content">
|
|
<div class="rst-content">
|
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
|
<ul class="wy-breadcrumbs">
|
|
<li><a href="..">Docs</a> »</li>
|
|
|
|
|
|
|
|
<li>Authentication</li>
|
|
<li class="wy-breadcrumbs-aside">
|
|
|
|
</li>
|
|
</ul>
|
|
<hr/>
|
|
</div>
|
|
<div role="main">
|
|
<div class="section">
|
|
|
|
<h1 id="listener-authentication">Listener Authentication</h1>
|
|
<p>Listener authentication is a feature of Icecast which allows you to secure a certain mountpoint such that in order to listen,
|
|
a listener must pass some verification test. With this feature, a simple pay-for-play operation (eg. user/pass), or some filtering
|
|
based on the listener connection can be performed. This section will show you the basics of setting up and maintaining this component. </p>
|
|
<p>To define listener authentication, a group of tags are specified in the <code><mount></code> group relating to the mountpoint. This means
|
|
that authentication can apply to listeners of source clients or relays. </p>
|
|
<p>The following authentication mechanisms can apply to listeners:</p>
|
|
<!-- FIXME -->
|
|
|
|
<ul>
|
|
<li>htpasswd: lookup a named file for a matching username and password</li>
|
|
<li>URL: issue web requests (eg. PHP) to match authentication</li>
|
|
</ul>
|
|
<p>The listener authentication within a specified mount in the icecast XML configuration can apply to either to a stream from a
|
|
source client, relay or a webroot based file. They do apply to intro files or fallback streams.</p>
|
|
<h1 id="htpasswd-listener-authentication">htpasswd Listener Authentication</h1>
|
|
<p>In order to use listener authentication, you <strong>must</strong> configure a mount specific option. This means that you have to provide
|
|
a <code><mount></code> section in the main icecast config file. The following is an example:</p>
|
|
<!-- FIXME -->
|
|
|
|
<pre><code class="xml"><mount>
|
|
<mount-name>/example.ogg</mount-name>
|
|
<authentication type="htpasswd">
|
|
<option name="filename" value="myauth"/>
|
|
<option name="allow_duplicate_users" value="0"/>
|
|
</authentication>
|
|
</mount>
|
|
</code></pre>
|
|
|
|
<p>To support listener authentication you <strong>must</strong> provide at a minimum <code><mount-name></code> and <code><authentication></code>.<br />
|
|
The <code>mount-name</code> is the name of the mountpoint that you will use to connect your source client with and <code>authentication</code> configures
|
|
what type of Icecast authenticator to use.<br />
|
|
Currently, only <code>htpasswd</code> and <code>url</code> are implemented. Each authenticator has a variable number of options that are required and
|
|
these are specified as shown in the example.<br />
|
|
The htpasswd authenticator requires a few parameters:<br />
|
|
The first, <code>filename</code>, specifies the name of the file to use to store users and passwords. Note that this file need not exist
|
|
(and probably will not exist when you first set it up).<br />
|
|
Icecast has built-in support for managing users and passwords via the web admin interface. More on this later in this section.<br />
|
|
The second option, <code>allow_duplicate_users</code>, if set to <code>0</code>, will prevent multiple connections using the same username. Setting this
|
|
value to <code>1</code> will enable mutltiple connections from the same username on a given mountpoint.<br />
|
|
Note there is no way to specify a “max connections” for a particular user. </p>
|
|
<p>Icecast supports a mixture of streams that require listener authentication and those that do not.</p>
|
|
<h2 id="configuring-users-and-passwords">Configuring Users and Passwords</h2>
|
|
<p>Once the appropriate entries are made to the config file, connect your source client (using the mountpoint you named in
|
|
the config file). To configure users and passwords for this stream you must use the web-based admin interface. Navigate to
|
|
<code>http://server:ip/admin/stats.xsl</code> to begin. If you have configured everything properly, you should see a screen like the
|
|
following:</p>
|
|
<p><img alt="Screenshot of Admin Stats" src="../img/listener_auth1.png" /></p>
|
|
<p>You will see a lock in front of all mountpoint configured for listener authentication. Also note that this page will
|
|
only show <em>connected</em> mountpoints.</p>
|
|
<p>To manage users and passwords for this mountpoint, click on the “Manage Authentication” link. The following screen will be shown:</p>
|
|
<p><img alt="Screenshot of Manage Authentication" src="../img/listener_auth2.png" /></p>
|
|
<p>This screen will show all the users configured for this mountpoint. Adding users is as simple as entering a username and password
|
|
in the fields and clicking “Add”.<br />
|
|
Note that usernames <strong>must</strong> be unique and there are <strong>no</strong> restrictions on passwords. You can delete users by clicking the appropriate
|
|
delete link next to each user.</p>
|
|
<h2 id="finishing-it-all-off">Finishing it all off</h2>
|
|
<p>Ok, so you've created your users, and you have everything setup properly, how do your users login? Well, we've provided a simple login
|
|
form that you can use for this purpose. This page (<code>http://server:port/auth.xsl</code>) will bring up a form that users can use to enter their
|
|
username and password.</p>
|
|
<p><img alt="Screenshot of Auth Page" src="../img/listener_auth3.png" /></p>
|
|
<p>This page will serve a m3u with the username and password and in most cases should open the correct media player and begin playing
|
|
your stream.</p>
|
|
<h1 id="url">URL</h1>
|
|
<p>Authenticating listeners via the URL method involves Icecast, when a listener connects, issuing requests to a web server
|
|
and checking the response headers. If a certain header is sent back then the listener connecting is allowed to continue,
|
|
if not, an error is sent back to the listener. </p>
|
|
<p>The URLs specified will invoke some web server scripts like PHP to do any work that they may choose to do. All that is
|
|
required of the scripting language is that POST information can be handled and response headers can be sent back.<br />
|
|
libcurl is used for the requesting so https connections may be possible, but be aware of the extra overhead involved. </p>
|
|
<p>The useragent sent in each curl request will represent the Icecast server version. The response headers will depend on
|
|
whether the listener is to be accepted. In the case of rejection, a response header<br />
|
|
<code>Icecast-Auth-Message: Reason</code><br />
|
|
should also be returned for placing in the log files. </p>
|
|
<p>In order to use URL based listener authentication, you <strong>must</strong> configure a mount specific option. This means that you
|
|
have to provide a <code><mount></code> section in the main Icecast config file. The following shows the list of options available: </p>
|
|
<!-- FIXME -->
|
|
|
|
<pre><code class="xml"><mount>
|
|
<mount-name>/example.ogg</mount-name>
|
|
<authentication type="url">
|
|
<option name="mount_add" value="http://auth.example.org/stream_start.php"/>
|
|
<option name="mount_remove" value="http://auth.example.org/stream_end.php"/>
|
|
<option name="listener_add" value="http://auth.example.org/listener_joined.php"/>
|
|
<option name="listener_remove" value="http://auth.example.org/listener_left.php"/>
|
|
<option name="username" value="user"/>
|
|
<option name="password" value="pass"/>
|
|
<option name="auth_header" value="icecast-auth-user: 1"/>
|
|
<option name="timelimit_header" value="icecast-auth-timelimit:"/>
|
|
<option name="headers" value="x-pragma,x-token"/>
|
|
<option name="header_prefix" value="ClientHeader."/>
|
|
<option name="stream_auth" value="http://auth.example.org/source.php"/>
|
|
</authentication>
|
|
</mount>
|
|
</code></pre>
|
|
|
|
<p>The options are described below in more detail, each of which is optional, but in each case, within the POST data,
|
|
the value for each setting is encoded.</p>
|
|
<!-- FIXME -->
|
|
|
|
<h2 id="mount_add">mount_add</h2>
|
|
<p>This URL is for informing the auth server of a stream starting. No listener information is passed for this,
|
|
but it can be used to initialise any details the auth server may have. </p>
|
|
<h3 id="post-details">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>mount_add</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint starting up</dd>
|
|
<dt>server</dt>
|
|
<dd>the server name (<code><hostname></code>)</dd>
|
|
<dt>port</dt>
|
|
<dd>the server port</dd>
|
|
</dl>
|
|
<h3 id="example">Example</h3>
|
|
<p><code>action=mount_add&mount=/live&server=icecast.example.org&port=8000</code></p>
|
|
<h2 id="mount_remove">mount_remove</h2>
|
|
<p>This URL is for informing the auth server of a stream finishing, like the start option, no listener details
|
|
are passed. </p>
|
|
<h3 id="post-details_1">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>mount_remove</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint being removed</dd>
|
|
<dt>server</dt>
|
|
<dd>the server name (<code><hostname></code>)</dd>
|
|
<dt>port</dt>
|
|
<dd>the server port</dd>
|
|
</dl>
|
|
<h3 id="example_1">Example</h3>
|
|
<p><code>action=mount_remove&mount=/live&server=icecast.example.org&port=8000</code></p>
|
|
<h2 id="listener_add">listener_add</h2>
|
|
<p>This is most likely to be used if anything. When a listener connects, before anything is sent back to them, this
|
|
request is processed. The default action is to reject a listener unless the auth server sends back a response header
|
|
which may be stated in the <code>header</code> option.</p>
|
|
<h3 id="post-details_2">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>listener_add</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint, including query parameters</dd>
|
|
<dt>server</dt>
|
|
<dd>the server name (<code><hostname></code>)</dd>
|
|
<dt>port</dt>
|
|
<dd>the server port</dd>
|
|
<dt>user</dt>
|
|
<dd>user as stated in listener HTTP basic auth<br />
|
|
<em>May be blank</em></dd>
|
|
<dt>pass</dt>
|
|
<dd>pass as stated in listener HTTP basic auth
|
|
<em>May be blank</em></dd>
|
|
<dt>client</dt>
|
|
<dd>unique ID for the client within Icecast</dd>
|
|
<dt>ip</dt>
|
|
<dd>listeners IP address</dd>
|
|
<dt>agent</dt>
|
|
<dd>useragent from the listeners player</dd>
|
|
</dl>
|
|
<p><strong>Note:</strong> The mount here (unlike the start/end options) states the requested url including any query parameters,
|
|
so for instance the requested URL can be <code>/stream.ogg&session=xyz</code>, but note that each option data is
|
|
escaped before being passed via POST.</p>
|
|
<h3 id="example_2">Example</h3>
|
|
<p><code>action=listener_add&server=icecast.example.org&port=8000&client=1&mount=/live&user=&pass=&ip=127.0.0.1&agent=My%20player</code> </p>
|
|
<h2 id="listener_remove">listener_remove</h2>
|
|
<p>This URL is for when a listener connection closes.</p>
|
|
<h3 id="post-details_3">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>listener_remove</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint</dd>
|
|
<dt>server</dt>
|
|
<dd>the server name (<code><hostname></code>)</dd>
|
|
<dt>port</dt>
|
|
<dd>the server port</dd>
|
|
<dt>user</dt>
|
|
<dd>user as stated in listener HTTP basic auth<br />
|
|
<em>May be blank</em></dd>
|
|
<dt>pass</dt>
|
|
<dd>pass as stated in listener HTTP basic auth
|
|
<em>May be blank</em></dd>
|
|
<dt>client</dt>
|
|
<dd>unique ID for the client within Icecast</dd>
|
|
<dt>ip</dt>
|
|
<dd>listeners IP address</dd>
|
|
<dt>agent</dt>
|
|
<dd>useragent from the listeners player</dd>
|
|
<dt>duration</dt>
|
|
<dd>number of seconds the listener was connected for</dd>
|
|
</dl>
|
|
<h3 id="example_3">Example</h3>
|
|
<p><code>action=listener_remove&server=icecast.example.org&port=8000&client=1&mount=/live&user=&pass=&duration=3600&ip=127.0.0.1&agent=My%20player</code></p>
|
|
<h2 id="stream_auth">stream_auth</h2>
|
|
<p>Technically this does not belong to listener authentication, but due to its similarity it is explained here too.<br />
|
|
When a source connects, before anything is sent back to them, this request is processed. The default action is to
|
|
reject a source unless the auth server sends back a response header which may be stated in the <code>header</code> option.</p>
|
|
<h3 id="post-details_4">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>stream_auth</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint</dd>
|
|
<dt>server</dt>
|
|
<dd>hostname of the Icecast server the client tries to connect to</dd>
|
|
<dt>port</dt>
|
|
<dd>the port of said server</dd>
|
|
<dt>user</dt>
|
|
<dd>username as sent by the source client</dd>
|
|
<dt>pass</dt>
|
|
<dd>password as sent by the source client</dd>
|
|
<dt>admin</dt>
|
|
<dd>admin request (read below)</dd>
|
|
</dl>
|
|
<p><strong>Note:</strong> As admin requests can come in for a stream (eg. metadata update) these requests can be issued while
|
|
stream is active. For these <code>admin</code> is set to <code>1</code> in POST details.</p>
|
|
<h3 id="example_4">Example</h3>
|
|
<p><code>action=stream_auth&mount=/stream.ogg&ip=192.0.2.0&server=icecast.example.org&port=8000&user=source&pass=password&admin=1</code></p>
|
|
<h2 id="other-options">Other Options</h2>
|
|
<dl>
|
|
<dt>auth_header</dt>
|
|
<dd>The expected response header to be returned that allows the authencation to take place may be specified here.<br />
|
|
The default is:<br />
|
|
<code>icecast-auth-user: 1</code><br />
|
|
but it could be anything you like, for instance:<br />
|
|
<code>HTTP 200 OK</code></dd>
|
|
<dt>timelimit_header</dt>
|
|
<dd>Listeners could have a time limit imposed on them, and if this header is sent back with a figure (which represents seconds)
|
|
then that is how long the client will remain connected for.</dd>
|
|
<dt>headers</dt>
|
|
<dd>This is a list of HTTP headers provided by the client which should be passed to the authencation service.
|
|
Those headers are prepended by the value of header_prefix and sent as POST parameters.</dd>
|
|
<dt>header_prefix</dt>
|
|
<dd>This is the prefix used for passing client headers. See headers for details.</dd>
|
|
</dl>
|
|
<h1 id="a-note-about-players-and-authentication">A note about players and authentication</h1>
|
|
<p>We do not have an exaustive list of players that support listener authentication.<br />
|
|
We use standard HTTP basic authentication, and in general, many media players support this if they support anything at all.
|
|
Winamp and Foobar2000 support HTTP basic authentication on Windows, and XMMS supports it on UNIX platforms. Winamp/XMMS at
|
|
least support the passing of query parameters, other players may also do.</p>
|
|
<h1 id="source-authentication">Source Authentication</h1>
|
|
<p>Source authentication is a feature of Icecast which allows you to secure a certain mountpoint such that in order to stream to it,
|
|
a source client must pass some verification test. This section will show you the basics of setting up and maintaining this component.<br />
|
|
To define source authentication, a group of tags are specified in the <code><mount></code> group relating to the mountpoint. </p>
|
|
<p>The following authentication mechanisms can apply to sources:</p>
|
|
<!-- FIXME -->
|
|
|
|
<ul>
|
|
<li>BASIC: <code><password></code> and possibly <code><username></code> in the <code><mount></code> section</li>
|
|
<li>URL: issue web requests (eg. PHP) to match authentication</li>
|
|
</ul>
|
|
<h2 id="url-authentication-stream_auth">URL authentication: <code>stream_auth</code></h2>
|
|
<p>A <code><mount></code> can contain a section <code><authentication type="url"></code> and therein
|
|
<code><option name="stream_auth" value="http://auth.example.org/source.php"/></code>. When a source connects, before anything is sent back to
|
|
them, this request is processed. The default action is to reject a source unless the auth server sends back a response header which may
|
|
be stated in the <code>header</code> option (same as listener auth). </p>
|
|
<h3 id="post-details_5">POST Details</h3>
|
|
<dl>
|
|
<dt>action</dt>
|
|
<dd><code>stream_auth</code></dd>
|
|
<dt>mount</dt>
|
|
<dd>the mountpoint</dd>
|
|
<dt>server</dt>
|
|
<dd>hostname of the Icecast server the client tries to connect to</dd>
|
|
<dt>port</dt>
|
|
<dd>the port of said server</dd>
|
|
<dt>user</dt>
|
|
<dd>username as sent by the source client</dd>
|
|
<dt>pass</dt>
|
|
<dd>password as sent by the source client</dd>
|
|
<dt>admin</dt>
|
|
<dd>admin request (read below)</dd>
|
|
</dl>
|
|
<p><strong>Note:</strong> As admin requests can come in for a stream (eg. metadata update) these requests can be issued while
|
|
stream is active. For these <code>admin</code> is set to <code>1</code> in POST details.</p>
|
|
<h3 id="example_5">Example</h3>
|
|
<p><code>action=stream_auth&mount=/stream.ogg&ip=192.0.2.0&server=icecast.example.org&port=8000&user=source&pass=password&admin=1</code></p>
|
|
|
|
</div>
|
|
</div>
|
|
<footer>
|
|
|
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
|
|
|
<a href="../relaying/" class="btn btn-neutral float-right" title="Relaying">Next <span class="icon icon-circle-arrow-right"></span></a>
|
|
|
|
|
|
<a href="../server_stats/" class="btn btn-neutral" title="Server Statistics"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
|
|
|
</div>
|
|
|
|
|
|
<hr/>
|
|
|
|
<div role="contentinfo">
|
|
<!-- Copyright etc -->
|
|
|
|
</div>
|
|
|
|
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
|
</footer>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
<div class="rst-versions" role="note" style="cursor: pointer">
|
|
<span class="rst-current-version" data-toggle="rst-current-version">
|
|
|
|
|
|
<span><a href="../server_stats/" style="color: #fcfcfc;">« Previous</a></span>
|
|
|
|
|
|
<span style="margin-left: 15px"><a href="../relaying/" style="color: #fcfcfc">Next »</a></span>
|
|
|
|
</span>
|
|
</div>
|
|
<script>var base_url = '..';</script>
|
|
<script src="../js/theme.js"></script>
|
|
|
|
</body>
|
|
</html>
|