├── .gitignore
├── 10-intro.md
├── 20-basics.md
├── 30-security.md
├── 40-interconnecting.md
├── 50-encryption.md
├── 60-database.md
├── 70-audio.md
├── _config.yml
├── _includes
├── footer.html
├── head.html
└── header.html
├── _layouts
├── default.html
├── page.html
└── post.html
├── _sass
├── _base.scss
├── _layout.scss
└── _syntax-highlighting.scss
└── css
└── main.scss
/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/10-intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Introduction
4 | permalink: /
5 | ---
6 |
7 | ## About
8 | This document is a collection of practical solutions and ideas - *recipes* - related to the [Yate telephony engine](http://yate.null.ro/). Recipes give specific solutions to specific problems encountered in real life. Some recipes were derived from practical experience during the 29th and 30th Chaos Communication Congress in Hamburg, Germany. Other solutions were encountered while setting up and maintaining our public VoIP provider [EPVPN](https://eventphone.de/epvpn) (Eventphone Virtual Phone Network).
9 |
10 | The technical minded person may find a jump start into Yate or use it as a reference guide.
11 | Personally I prefer to write down experiences before they slip my mind and may be lost forever.
12 | Please feel free to share this document (under the terms of this document's license). Information wants to be free.
13 |
14 | ## The Author
15 |
16 | Ben Fuhrmannek is a computer scientist with a background in software development and IT security. In his spare time, among other things, he likes to indulge in open communication.
17 |
18 | For more information check out my list of [presentations and papers](http://www.fuhrmannek.de/pnp/).
19 |
20 | ## Alternatives to Yate
21 |
22 | The eventphone team has been evaluating VoIP software since 2004. And we came across quite a few working solutions for our use case: Provide secure, stable and reliable VoIP connectivity for more than 1000 hackers during conferences. This is my personal opinion:
23 |
24 | * **PBX4Linux, now LCR:** LCR comes with the idea of an ISDN PBX, now with SIP connectivity. We are using LCR as our central routing mechanism to interconnect DECT, Yate, Asterisk, GSM and Dialin/Dialout.
25 | * **Asterisk (and many forks):** This PBX opened my eyes in regard to programming VoIP applications. AGI and AEL are quite powerful interfaces and very intuitively programmed. Complex IVRs, games, automated calls and many more features make this PBX software almost perfect for every use case. However, there has not been a single hacker event without the need for a *while-true* loop to restart asterisk every hour or so. A similar setup with Yate lasted the whole 29c3 and 30c3 without a single unscheduled restart. The people of the rather popular [Gemeinschaft PBX](http://amooma.de/gemeinschaft) seem to come to a similar [conclusion](http://www.freeswitch.org/node/373) and switched from Asterisk to FreeSWITCH: "FreeSWITCH is better, more stable, more secure and gives higher performance."
26 | * **FreeSWITCH:** This PBX caught my attention because it took me about 10 minutes form download to the first call. Configuration files are XML, there are many (maybe even a lot of) modules available and the PBX can be scripted in every popular scripting language. Hardware support seemed a bit limited at the time - in 2005 I found only Sangoma ISDN card drivers. An alpha version of mISDN worked just fine when I tried it. Just like VIM vs. Emacs, RISC vs. CISC, for me this is a tie between FreeSWITH and Yate.
27 | * **OpenSER / Kamaillo / OpenSIPS:** These *Open Source SIP Servers* seem to focus on SIP and do their job well.
28 | * **YXA:** As a friend of software written in Erlang, particularly PBX software, this SIP router could have been a good successor for Asterisk. However after a day or so of configuration efforts I chose to focus on alternatives.
29 |
30 |
31 | ## License
32 |
33 | This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
34 |
35 | You are free to:
36 |
37 | * **Share** — copy and redistribute the material in any medium or format
38 | * **Adapt** — remix, transform, and build upon the material
39 |
40 | for any purpose, even commercially.
41 |
42 | Under the following terms:
43 |
44 | * **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
45 |
46 | **No additional restrictions** — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
47 |
48 | ## Referencing Guideline
49 |
50 | When quoting or referencing this document, it is good style to mention
51 |
52 | * **the author's name:** Ben Fuhrmannek - *Note: Derivative and contributed work may have a different author or several authors as indicated on the page or chapter.* The github username - here @bef - is sufficient when referencing on github.
53 | * **document title:** {{ site.title }}
54 | * **document version, revision or date**: see [https://github.com/{{ site.github_project }}](https://github.com/{{ site.github_project }}) for the latest change. If unsure, use the access date.
55 | * **original URL:** https://bef.github.io{{ site.baseurl }}
56 |
57 | *Note:* Be aware, that the document, URLs and the document structure may change over time. It's best not to share a specific URL only, but rather a descriptive reference including chapter name.
58 |
59 | ### Examples:
60 |
61 | * Example reference in print:
62 |
63 | Fuhrmannek, B. (2014-10-01) {{ site.title }}. (Internet). Available from {{ site.projecturl }}. Accessed 29.06.2048.
64 |
65 | * Formal web reference:
66 |
67 | {{ site.title }} by Ben Fuhrmannek
68 |
69 | * Casual web reference (specific chapter) when referencing from github:
70 |
71 | See {{ site.title }} / Security.
72 |
73 | ### Bad Examples:
74 |
75 | * See here. *(no title)*
76 | * Look what I did: ... *(invalid attribution)*
77 | * Ad. Ad. (this work)... Ad. Ad. *(bad context: The document has been released with a commercial use license. But using my name or work in connection with link spam sites is just wrong.)*
78 |
79 |
--------------------------------------------------------------------------------
/20-basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Yate Basics
4 | permalink: /basics/
5 | ---
6 |
7 | This chapter will provide a basic understanding of how to install, configure and debug Yate. Please feel free to skip to the next chapter if your Yate installation is already up and running properly.
8 |
9 | ## Documentation
10 |
11 | Where can I get more information?
12 |
13 | * [http://docs.yate.ro/](http://docs.yate.ro/) - up-to-date documentation wiki with lots of articles
14 | * [http://yate.null.ro/](http://yate.null.ro/) - slightly out-of-date documentation wiki, but still useful
15 | * Source Code / RTFS - The source code is well structured C++ and very easy to read. Give it a try.
16 | * [http://yate.null.ro/pmwiki/index.php?n=Main.MailList](http://yate.null.ro/pmwiki/index.php?n=Main.MailList) - the Yate mailing list and its archive
17 |
18 | ## Quick Installation
19 |
20 | You may choose to install Yate from your operating system's package repository, e.g. on Debian Linux:
21 |
22 | # apt-get install yate
23 |
24 | However, keep in mind that your OS may not include the latest Yate version, which can be problematic in regard to security and feature set. On the other hand, packages are easier to maintain.
25 |
26 | ### Install from Source
27 |
28 | 1. Download latest version from [http://yate.null.ro/](http://yate.null.ro/) and unpack the archive as usual, e.g.
29 |
30 | $ cd /usr/local/src
31 | $ wget http://yate.null.ro/tarballs/yate5/yate-XXXXX.tar.gz ## replace XXXXX with actual version number
32 | $ tar zxvf yate-XXXXX.tar.gz
33 | $ cd yate
34 |
35 | *Note:* If you are upgrading, be aware that the archive contains the directory `yate/`, which may already exist. --> `cp yate yate-xxx` first.
36 |
37 | 2. Install dependencies, e.g. on Debian/Ubuntu:
38 |
39 | # apt-get install build-essential zlib1g-dev libssl-dev libgsm1-dev pkg-config speex
40 | # apt-get install libmysqlclient-dev ## for mysql support if needed
41 |
42 | 3. Configure with flags, e.g. with custom install path, without Postgres support and with SSE2:
43 |
44 | $ ./configure --prefix=/home/poc/yate --without-libpq --enable-sse2
45 |
46 | Or simply run the default configure:
47 |
48 | $ ./configure
49 |
50 | Personally I like to keep this line and additional installation instructions and notes close to the actual installation in a file like `../COMPILE_YATE`. This way I know exactly how to re-compile or upgrade the software several months later for this particular installation.
51 |
52 | 4. Compile + Install
53 |
54 | $ make
55 | $ sudo make install
56 |
57 | Don't worry. There is a working `make uninstall`, which deletes all but configuration files.
58 |
59 | After installation, files can be found in the usual places. Assuming an installation prefix of `/usr/local`:
60 |
61 | * `/usr/local/etc/yate`: configuration files
62 | * `/usr/local/bin/yate*`: executable files
63 | * `/usr/local/share/yate/*`: support files: scripts, sounds, UI files
64 | * `/usr/local/man/man8/yate*`: manual pages
65 | * `/usr/local/share/doc/yate-*`: developer documentation
66 | * `/usr/local/lib/yate/*`: yate modules
67 | * `/usr/local/lib/libyate*`: shared libraries
68 | * `/usr/local/include/yate`: include files
69 | * depending on your configuration there may be other support files
70 |
71 | ### Upgrade from Source
72 |
73 | 1. Stop Yate, e.g. `killall yate`
74 | 2. `make uninstall` in the old Yate source directory: This will remove version specific libraries
75 | 3. `make install` in the new Yate source directory: This will install the new Yate version and not harm any existing configuration files.
76 | 4. Update configuration if needed, e.g. new modules.
77 | 5. Start Yate
78 |
79 |
80 | ### Configuration
81 |
82 | Yate configuration files are like INI files with `[sections]` and `key=value` pairs. For syntax highlighting in VIM just type `:setf dosini` and `:syntax on` or extend your `.vimrc` like so:
83 |
84 | ```vim
85 | " yate -> dosini syntax
86 | au BufNewFile,BufRead */etc/yate/*.conf setf dosini
87 |
88 | " syntax highlighting
89 | syn on
90 | ```
91 |
92 | Config files reside in `/usr/local/etc/yate/` by default. Let's start with `yate.conf`: It is a good idea only to load those modules actually needed for your setup. Otherwise it may lead to unwanted features or protocols being enabled, which in turn broadens the attack surface from a security point of view.
93 |
94 | The following example shows a usable `yate.conf` restricted to load only a few modules on startup:
95 |
96 | ```INI
97 | [general]
98 | ; modload: boolean: Should a module be loaded by default if there is no
99 | ; reference to it in the [modules] section
100 | modload=disable
101 |
102 | ;...
103 |
104 | [modules]
105 | dumbchan.yate=true
106 | lateroute.yate=true
107 | regfile.yate=true
108 | accfile.yate=true
109 | rmanager.yate=true
110 | wavefile.yate=true
111 | pbx.yate=true
112 | tonegen.yate=true
113 | callfork.yate=true
114 | ysipchan.yate=true
115 | extmodule.yate=true
116 | yrtpchan.yate=true
117 | openssl.yate=true
118 | regexroute.yate=true
119 | ;ilbcwebrtc.yate=true
120 | ;cdrbuild.yate=true
121 | ;cdrfile.yate=true
122 | ;javascript.yate=true
123 | ;...
124 | ```
125 |
126 | I like to add all available modules commented out to the [modules] section to be able to toggle modules with minimal effort. Try the following command:
127 |
128 | find /usr/local/lib/yate -name \*.yate |xargs -n 1 basename |xargs -n 1 -I '{}' echo ";{}=true"
129 |
130 | As a rule: If you don't know the module, best leave it commented out. See also [the Yate docu Wiki](http://docs.yate.ro/wiki/Modules) for a list of modules.
131 |
132 | *Next step:* Configure each module loaded on startup.
133 |
134 |
135 | ## Startup
136 |
137 | Yate can run as unprivileged system user. I fact, creating a dedicated user and group just for running Yate is a security recommendation. So:
138 |
139 | # groupadd yate
140 | # useradd -g yate yate
141 | # mkdir /home/yate
142 | # chown yate:yate /home/yate
143 | # su - yate
144 | $
145 |
146 |
147 | There are several ways to start Yate:
148 |
149 | * For debugging right after compilation: There is a script in the source directory `./run` to start and debug Yate on Linux systems.
150 |
151 | * For debugging and first setup after installation: Just type `yate` or `yate -v` or even `yate -Do -vv` (`-Do` means color output; `-vv` means 2x verbose).
152 |
153 | The following error may occur:
154 |
155 | yate: error while loading shared libraries: libyate.so.4.3.0: cannot open shared object file: No such file or directory
156 |
157 | If so, try `LD_LIBRARY_PATH=/usr/local/lib yate` or add the correct library path to your dynamic loader search path, e.g. `/etc/ld.so.conf` and run `ldconfig`. On MacOSX the dynamic linker uses the environment variable `DYLD_LIBRARY_PATH`.
158 |
159 | Also quite useful in this context is [SCREEN](http://www.gnu.org/software/screen/) or any other terminal multiplexer program.
160 |
161 | * For production: The source package comes with a few sample init scripts:
162 |
163 | ./packing/deb/yate.init
164 | ./packing/portage/yate.init
165 | ./packing/rpm/yate.init
166 |
167 |
168 | After successful startup you can see where Yate is listening for connections:
169 |
170 | $ sudo netstat -lntup |grep yate
171 |
172 | On my test VM the output looks like this:
173 |
174 | ```
175 | tcp 0 0 127.0.0.1:5060 0.0.0.0:* LISTEN 28833/yate
176 | tcp 0 0 172.16.229.129:5061 0.0.0.0:* LISTEN 28833/yate
177 | tcp 0 0 127.0.0.1:5038 0.0.0.0:* LISTEN 28833/yate
178 | tcp 0 0 127.0.0.1:5039 0.0.0.0:* LISTEN 28833/yate
179 | udp 0 0 172.16.229.129:5060 0.0.0.0:* 28833/yate
180 | udp 0 0 0.0.0.0:4569 0.0.0.0:* 28833/yate
181 | ```
182 |
183 | Port 5060 is for SIP. Port 2061 is for SIPS (SIP over TLS). Port 4569 is IAX. Port 5038 is the rmanager and port 5039 is an extmodule listener.
184 |
185 |
186 | ## Debugging
187 |
188 | ### Restarting Yate
189 |
190 |
191 | * Full restart: `/etc/init.d/yate restart`
192 | or equivalently Ctrl-C, Cursor-UP, RETURN.
193 |
194 | * Reload Yate: Send SIGQUIT to the Yate process:
195 |
196 | killall -SIGQUIT yate
197 |
198 | Or press `Ctrl-\` on the running foreground process - however this may detach shell scripts if Yate was started using a custom startup script.
199 |
200 | Or press `Ctrl-\` in rmanager.
201 |
202 |
203 | ### rmanager
204 |
205 | The rmanager is a useful Yate console. A most common configuration is done like so in `rmanager.conf`:
206 |
207 | ```INI
208 | [general]
209 | ; Each section creates a connection listener in the Remote Manager.
210 | ; An empty (all defaults) general section is assumed only in server mode if the
211 | ; configuration file is missing.
212 |
213 | ; port: int: TCP Port to listen on, 0 to disable the listener
214 | port=5038
215 |
216 | ; addr: ipaddress: IP address to bind to
217 | addr=127.0.0.1
218 |
219 | ;...
220 | ; color: bool: Enable colorization debug as soon as connecting
221 | ; This setting is ignored if telnet negotiation is disabled
222 | color=yes
223 | ;...
224 | ```
225 |
226 | Then, connect using telnet or netcat:
227 |
228 | ```
229 | $ telnet localhost 5038
230 | Trying ::1...
231 | Trying 127.0.0.1...
232 | Connected to localhost.
233 | Escape character is '^]'.
234 | eventphone YATE 4.3.0-1 on devvm.
235 | ```
236 |
237 | Try `help` and `status`. For more debugging output, try this (for verbose SIP debugging):
238 |
239 | debug on
240 | debug level 10
241 | debug sip level 10
242 |
243 |
244 | Possible debug levels can be found in `yateclass.h` line 225++:
245 |
246 |
247 | ```
248 | enum DebugLevel {
249 | DebugFail = 0,
250 | DebugTest = 1,
251 | DebugGoOn = 2,
252 | DebugConf = 3,
253 | DebugStub = 4,
254 | DebugWarn = 5,
255 | DebugMild = 6,
256 | DebugCall = 7,
257 | DebugNote = 8,
258 | DebugInfo = 9,
259 | DebugAll = 10
260 | };
261 | ```
262 |
263 |
264 | ### IP level SIP debugging
265 |
266 | Usual candidates would be
267 |
268 | # ngrep -l -W byline port 5060
269 |
270 | # tcpdump -ln -i eth0 -A port 5060
271 |
272 |
273 |
274 | ## Concepts
275 |
276 | ### Engine / Message Queue
277 |
278 | The core of Yate - the engine - is a message queue. Each module can subscribe to a type of message and either process or reject the message. In addition, Yate modules can also observe the message queue without actually handling messages (watch), which is similar to a [PubSub pattern](https://en.wikipedia.org/wiki/Publish/subscribe).
279 |
280 | When subscribing to a message type, the module must provide a priority. A message is then passed to each matching module in the order of subscribed priority.
281 |
282 | Messages are human readable. Try this in rmanager:
283 |
284 | ```
285 | machine on
286 | Machine mode: on
287 | %%::[]:[:=...]
295 |
296 | The message dumped here is of type `engine.timer` and was sent from *Engine to Application*. There is no `id`. The message has not been processed by any module (processed=false). The return value is empty. At the end there are multiple key/value pairs, notably *handlers=...*, which lists all modules subscribed to this message type and their priority.
297 |
298 | The complete message format documentation can be found [here](http://yate.null.ro/docs/extmodule.html) as well as in the source package under `docs/extmodule.html`.
299 |
300 | A common message flow for a Call from a user to an IVR would look like this:
301 |
302 | call.preroute
303 | chan.startup
304 | call.route
305 | call.update
306 | call.execute
307 | chan.rtp status=created
308 | chan.connected
309 | ...
310 | chan.rtp status=terminated
311 | chan.hangup
312 | chan.disconnected
313 |
314 |
315 | A list of standard messages can be found in the [documentation](http://docs.yate.ro/wiki/Standard_Messages). Custom modules may invent new message types and use the Yate engine to do IPC (inter-process communication).
316 |
317 |
318 | ### Extmodule
319 |
320 | Participating in the Yate engine's message queue without writing another module in C++ (which would be simple enough) is done via the *extmodule* module. `extmodule.conf`:
321 |
322 | ```INI
323 | [general]
324 | scripts_dir=/usr/local/share/yate/scripts/
325 | priority=100
326 | timeout=10000
327 | timebomb=true
328 | ;...
329 |
330 | [listener tcp5039]
331 | type=tcp
332 | addr=127.0.0.1
333 | port=5039
334 | ```
335 | This configuration opens a TCP socket on port 5039. It is also possible to call scripts, that communicate via stdio, like so: `regexroute.conf`:
336 |
337 | ^77$=external/nodata/foo.tcl
338 |
339 | This would execute the script `/usr/local/share/yate/scripts/foo.tcl` and interact using the extmodule protocol.
340 |
341 | *Note*: Some examples in this document are written in Tcl using the [YGI library](https://github.com/bef/yate-tcl) to interface with Yate. Libraries in other languages - PHP, Python, Perl - are available as well. Yate also comes with its own JavaScript interpreter in its own module *javascript.yate*.
342 |
343 | A simple use case for extmodule is YGI's message printer `dumpmsgs.tcl`:
344 |
345 | ```
346 | ---------> new message: user.register true
347 | | number 3333
348 | | sip_uri sip:devvm
349 | | sip_callid 2088059556@devvm
350 | | username 3333
351 | | realm devvm
352 | | ip_transport TLS
353 | | newcall false
354 | | domain devvm
355 | | device YATE/4.0.1
356 | | driver sip
357 | | data sip/sip:3333@172.16.229.1:62928
358 | | ip_host 172.16.229.1
359 | | ip_port 62928
360 | | expires 600
361 | | sip_to sip:3333@172.16.229.1:62928
362 | | connection_id tls:172.16.229.129:5061-172.16.229.1:62928
363 | | connection_reliable true
364 | | route_params oconnection_id
365 | | oconnection_id tls:172.16.229.129:5061-172.16.229.1:62928
366 | | handlers monitoring:1,register:50
367 | ...
368 | ```
369 |
370 |
--------------------------------------------------------------------------------
/30-security.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Security
4 | permalink: /security/
5 | ---
6 |
7 |
8 | This security checklist is a good start to harden your VoIP setup:
9 |
10 | * **Principle of minimal privilege:** Try to restrict your setup as much as possible to do exactly what you intended it to do, not more. This principle implicitly applies to all of the following points.
11 |
12 | * **Operating System:**
13 |
14 | * Use virtual environments, such as Xen, VirtualBox, OpenVZ, ...
15 | * Use a chroot environment.
16 | * Run Yate with a dedicated system user and group.
17 | * Set ulimits to prevent resource exhaustion.
18 | * Use application security systems, e.g. AppArmor.
19 | * Don't run any other server software on the system.
20 | * Don't let many users access the system.
21 | * Log admin access.
22 |
23 |
24 | * **Filesystem:** Restrict access to files:
25 |
26 | * Yate files, scripts and modules should be owned by a different system user than the user that runs Yate. E.g.
27 |
28 | chown -R root:yate /usr/local/etc/yate /usr/local/share/yate
29 |
30 | * Files should be set read-only for the user that runs Yate. E.g.
31 |
32 | chmod -R go-w /usr/local/etc/yate /usr/local/share/yate
33 |
34 | * Files containing passwords or other sensitive information should be set unreadable for others:
35 |
36 | cd /usr/local/etc/yate
37 | chmod 640 accfile.conf regfile.conf mysqldb.conf
38 |
39 | * Consider using encrypted filesystems to protect sensitive data, e.g. voicemail messages or remote VoIP account credentials.
40 |
41 |
42 | * **IP Network:**
43 |
44 | * Set up a firewall to restrict access to SIP, rmanager, extmodule, ... and don't forget IPv6.
45 | * Set up flood protection, e.g. fail2ban.
46 | * Use a VPN to restrict access to access all or parts of Yate.
47 | * Configure management services like rmanager and extmodule to listen on localhost only.
48 | * Configure a dedicated VLAN for VoIP traffic.
49 | * Protect switch ports with IEEE 802.1x if possible.
50 | * Set switch ports to be disabled after link is down.
51 |
52 |
53 | * **Database:**
54 |
55 | * Write your SQL statements with caution: Only use appropriately escaped or whitelisted values in dynamic queries in order to prevent [SQL injection](https://www.owasp.org/index.php/SQL_injection) attacks. Keep in mind, that variables may contain user provided values, such as user agent, caller ID or custom SIP headers.
56 | * Restrict Yate database user to DELETE, INSERT, SELECT, USAGE, UPDATE. There is no reason for the database to be dropped or altered by a phone call.
57 | * Think about rejecting suspicious database queries by whitelisting or blacklisting queries before execution using the *regexroute* module.
58 |
59 |
60 | * **SIP Security:**
61 |
62 | * Only allow SIP methods actually needed, e.g. disable OPTIONS.
63 | * Don't enable subscribe/notify features to unauthenticated users.
64 | * Don't leak information about server software versions to the outside. Change the default SIP header *Server:* (or *User-Agent:* for SIP clients) to omit version numbers: `ysipchan.conf`:
65 |
66 | useragent=Foo
67 |
68 | * Filter traffic to other networks, e.g. with a Session Border Controller (SBC).
69 |
70 |
71 | * **VoIP routing and dialplan considerations:**
72 |
73 | * Avoid routing loops. Yate has an internal loop detection. But bouncing calls from one VoIP server to another and back several times will exhaust resources and provide attackers with a deny-of-service attack surface.
74 | * Restrict internal numbers to authenticated clients.
75 | * Categorise clients by source IP, if possible. E.g. internal clients may always have an internal IP.
76 | * Protect your dialout. Anonymous users or SIP scanners should not be able to generate charges on your telephone bill.
77 | * Never trust an incoming caller ID. Caller IDs can be faked, is PSTN as well as in VoIP. Also: Obscure caller IDs should be rejected or rewritten at an early routing stage, e.g. allow only digits 0-9, A-D and maybe allow the international `+' character in some cases.
78 | * Do not allow users to change their caller ID, e.g. set caller ID based on the authenticated username.
79 | * Explain your dialplan. Draw diagrams. Write tables. Fill Wikis. Anything. Please.
80 | * Test your configuration. In particular, regular expressions as used to create a dialplan with the *regexroute* module can be tricky.
81 |
82 |
83 |
84 | * **Passwords:**
85 |
86 | * Generate strong and random user passwords, e.g. with [APG](http://www.adel.nursat.kz/apg/).
87 | * If possible, avoid passwords at all, but use certificates or hardware tokens instead.
88 | * Protect phone applications, e.g. voicemail, with passcodes longer than four digits. If possible, add additional checks for valid caller-IDs, user authentication credentials, IPs, time of day or other criteria.
89 | * Users must be able to change their passwords and PINs on their own. They should also be made aware of this feature.
90 |
91 |
92 |
93 | * **Update Strategy:**
94 |
95 | * Regularly check for new versions.
96 | * Know how to easily update Yate. Take notes on how to compile, deploy, install, upgrade Yate to make life easier for the future you or possibly for other administrators. Also: Store notes where they can be found, e.g. in a file `../YATE_NOTES.txt` or a documentation wiki (or even an offline notebook).
97 |
98 |
99 |
100 | * **Transport Encryption:** Consider setting up encryption if possible:
101 |
102 | * Enable SIP over TLS (SIPS).
103 | * Enable SRTP.
104 | * As a client, validate certificates in order to prevent man-in-the-middle attacks.
105 | * Consider enforcing encrypted calls - SIPS + SRTP - for some numbers, e.g. confidential conference rooms.
106 | * For performance reasons it may be better to use VPN solutions - e.g. IPSec or OpenVPN - for point-to-point links in some cases.
107 |
108 |
109 | * **No Logging:**
110 |
111 | * Log nothing unless absolutely required. For personal use, this may be unnecessary. For business use it may even be against privacy laws to store connection data.
112 | * Think about logging only statistics - e.g. usage counters - without associated names/numbers.
113 | * A cronjob should be in place to delete old data.
114 |
115 |
116 | * **Monitoring:** Set up monitoring software in order to know when something went wrong.
117 |
118 | * **Security Checks:** Implement as many security features as possible and check them on a regular basis.
119 |
120 | * **Disaster Recovery:** Keep your VoIP setup well documented and create automated backups on a regular basis. It should be well known what to do after discovering a security incident - for example:
121 |
122 | * Disconnect from the internet.
123 | * Restore VoIP setup to a defined state.
124 | * Find and fix vulnerability, e.g. upgrade software.
125 | * Change all passwords, PINs, SSH keys, ... and revoke certificates.
126 | * Inform users.
127 |
128 |
--------------------------------------------------------------------------------
/40-interconnecting.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Interconnecting
4 | permalink: /interconnecting/
5 | ---
6 |
7 | ## Connecting LCR
8 |
9 | ```
10 | ------------- -------------
11 | | Yate |-----------| LCR |
12 | |172.16.40.2| (SIP) |172.16.40.1|
13 | ------------- -------------
14 | ```
15 |
16 | Running Yate and [LCR (Linux Call Router)](http://www.linux-call-router.de) on the same host - e.g. localhost - is possible. However if the setup is more complicated - e.g. Yate + Asterisk + LCR or several Yates and LCR or several LCRs - you can save a lot of time and effort by separating each VoIP server into its own (virtual) environment with its own network interface. Just keep in mind, that real hardware access may require PCI passthru or equivalent for better timing.
17 |
18 | `LCR interface.conf`:
19 |
20 | [Yate_SIP]
21 | #sip [:] [:]
22 | sip 172.16.40.1:5061 172.16.40.2
23 | earlyb no
24 | tones yes
25 |
26 | If not already covered by the a listener define another listener in `Yate ysipchan.conf`:
27 |
28 | [listener lcr]
29 | enable=yes
30 | addr=172.16.40.2
31 | port=5060
32 |
33 |
34 | Routing from LCR to Yate is shown by the following example. Calling *01980123* will call *123* via interface Yate_SIP. Calling *01999123* will call *01999123* as the `goto` does not consume matched digits.
35 | `LCR routing.conf`:
36 |
37 | [main]
38 | dialing=01980 : extern interfaces=Yate_SIP
39 | dialing=01999 : goto ruleset=to_yate
40 |
41 | [to_yate]
42 | : extern interfaces=Yate_SIP
43 |
44 |
45 | Routing from Yate to LCR is done the usual way - assuming 0... will be routed to LCR:
46 | `Yate regexroute.conf`:
47 |
48 | ^\(0.*\)$=sip/sip:\1@172.16.40.1:5061
49 |
50 |
51 | *Note*: Try to avoid routing loops.
52 |
53 |
54 | ## Connecting Asterisk (Scenario 1)
55 |
56 | N-to-N trunking without registration or authentication via SIP protocol - (assuming VPN or other trust relationship between hosts and static IPs):
57 |
58 | ```
59 | -------- ------------
60 | | Yate |----SIP----| Asterisk |
61 | -------- ------------
62 | ```
63 |
64 | `Asterisk sip.conf` for incoming calls:
65 |
66 | ```INI
67 | [world]
68 | type=peer
69 | host=office.example.com
70 | context=default
71 | permit=192.168.88.99/255.255.255.255
72 | ```
73 |
74 | Calling from Yate to Asterisk: - assuming a two-digit extension: `Yate regexroute.conf`
75 |
76 | ```INI
77 | ^..$=sip/sip:\0@192.168.88.98
78 | ```
79 |
80 | Calling from Asterisk to Yate: `Asterisk extensions.ael`
81 |
82 | ```
83 | context internal {
84 | _X. => {
85 | Dial(SIP/${EXTEN}@192.168.88.99);
86 | Hangup;
87 | };
88 | };
89 | ```
90 |
91 | ## Connecting Asterisk (Scenario 2)
92 |
93 | Yate registers to Asterisk via IAX2 protocol.
94 |
95 | ```
96 | -------- -------- ------------ ---------
97 | | PSTN |<---| Yate |--(IAX2)-->| Asterisk |--->| Phones|
98 | -------- -------- ------------ ---------
99 | ```
100 |
101 | This is one practical solution for N-to-N trunking with registration and two way password authentication. The opposite direction where Asterisk registers to Yate would be more straight forward, however routing from Yate to Asterisk can become rather complicated.
102 |
103 | `Asterisk sip.conf`:
104 |
105 | ```INI
106 | [world]
107 | type=friend
108 | ;host=office.example.com
109 | host=dynamic
110 | secret=SECRET_PASSWORD_HERE
111 | context=default
112 | permit=192.168.88.99/255.255.255.255
113 | ```
114 |
115 | `Yate accfile.conf` for registration and outgoing connections:
116 |
117 | ```INI
118 | [office]
119 | enabled=yes
120 | protocol=iax
121 | username=world
122 | password=SECRET_PASSWORD_HERE
123 | server=192.168.88.98
124 | interval=30
125 | ```
126 |
127 | `Yate regfile.conf` for incoming connections:
128 |
129 | ```INI
130 | [x1]
131 | password=SECRET_PASSWORD_HERE
132 | ```
133 |
134 | Calling from Yate to Asterisk - assuming a two-digit extension: `Yate regexroute.conf`:
135 |
136 | ```INI
137 | ^..$=line/\0;line=office
138 | ```
139 |
140 | Calling from Asterisk to Yate: `Asterisk extensions.ael`:
141 |
142 | ```
143 | context internal {
144 | _X. => {
145 | Dial(IAX2/x1:SECRET_PASSWORD_HERE@192.168.88.99/${EXTEN});
146 | Hangup;
147 | };
148 | };
149 | ```
150 |
151 |
--------------------------------------------------------------------------------
/50-encryption.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Encryption
4 | permalink: /encryption/
5 | ---
6 |
7 | ## TLS Encryption (SIPS/SRTP Server)
8 |
9 |
10 | These few steps will enable TLS for SIP and RTP in Yate:
11 |
12 | 1. Get or create a certificate, e.g. create a self-signed certificate:
13 |
14 | openssl genrsa -out key.pem 2048
15 | openssl req -new -key key.pem -out request.pem
16 | openssl x509 -req -days 3650 -in request.pem -signkey key.pem -out certificate.pem
17 | chmod 400 *.pem
18 |
19 | key.pem and certificate.pem can be moved to /usr/local/etc/yate/ssl.
20 |
21 | 2. Configure the openssl module: `openssl.conf`
22 |
23 | ```INI
24 | [general]
25 |
26 | [server_context]
27 | enable=yes
28 | domains=voip.example.com
29 | certificate=ssl/certificate.pem
30 | key=ssl/key.pem
31 | ```
32 |
33 | And enable openssl.yate in yate.conf (set openssl.yate=true in section [modules]). The created [server_context] can be used by several modules: jabberserver, ysipchan, rmanager
34 |
35 | 3. Configure SIP module: `ysipchan.conf`
36 |
37 | ```INI
38 | [general]
39 | ;...
40 | secure=enable
41 | ;...
42 | [listener ssl]
43 | enable=yes
44 | type=tls
45 | ;addr=172.16.88.12
46 | port=5061
47 | sslcontext=server_context
48 | ```
49 |
50 | 4. Configure all your clients to accept the generated certificate as valid.
51 |
52 |
53 | Optional steps:
54 |
55 | * DNS configuration:
56 | Set NAPTR and SRV records. [NAPTR](https://en.wikipedia.org/wiki/NAPTR_record) (Name Authority Pointer) records provide a way to point to the correct VoIP resource and may even contain a regular expression to rewrite the request.
57 | [SRV](https://en.wikipedia.org/wiki/SRV_record) records point services to hostnames and ports.
58 |
59 | example.com. IN NAPTR 10 0 "s" "SIPS+D2T" "" _sips._tcp.example.com.
60 | example.com. IN NAPTR 20 0 "s" "SIP+D2T" "" _sip._tcp.example.com.
61 | example.com. IN NAPTR 30 0 "s" "SIP+D2U" "" _sip._udp.example.com.
62 | _sips._tcp.example.com. IN SRV 10 0 5061 voip.example.com.
63 | _sip._udp.example.com. IN SRV 10 0 5060 voip.example.com.
64 | _sip._tcp.example.com. IN SRV 10 0 5060 voip.example.com.
65 |
66 | This example contains a complete set of entries for SIPS, SIP over UDP and SIP over TCP. If you have only enabled listeners for one or two of these services, then don't set the others.
67 |
68 | * Encourage the use of encryption by blocking some (or all) numbers for unencrypted connections: `regexroute.conf`:
69 |
70 | ```INI
71 | ^8044$=if ${ip_transport}^TLS$=if ${encryption}.=if ${crypto}.=conf/tlsonly;maxusers=23;lonely=true
72 | ```
73 |
74 | This will allow participants to enter a conference room (`conf/tlsonly`) when the signaling connection is TLS encrypted (e.g. SIPS) and also data encryption is offered. *Note*: At this point, the client may still negotiate to use an unencrypted data channel or renegotiate the data channel later.
75 |
76 | * Store `oconnection_id` in user database:
77 | In order to call clients connected by TLS (or TCP), Yate needs to be able to find the TCP connection associated with the client. This is done by looking up (and setting) the channel variable `oconnection_id`. (Actually, the channel variable `route_params` contains a list of variables to be looked up for routing, but for this use case it's just `oconnection_id`.) The file backend (regfile module) can do this automatically. Database backends must store this field explicitly.
78 |
79 |
--------------------------------------------------------------------------------
/60-database.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Database
4 | permalink: /database/
5 | ---
6 |
7 | ## MySQL Users and Routing
8 |
9 | The *register* module provides an SQL database backend to user registration. This is an example configuration for MySQL. (The module can also be used for CDR and subscription features, which have been left out for simplicity.)
10 |
11 | `mysqldb.conf:`
12 |
13 | ```INI
14 | [default]
15 | ;host=
16 | ;port=0
17 | database=yate
18 | user=yate
19 | password=mypassword
20 | ;socket=
21 | ;compress=disable
22 | encoding=utf8
23 | poolsize=1
24 | ```
25 |
26 | `register.conf:`
27 |
28 | ```INI
29 | [general]
30 | expires=30
31 | user.auth=yes
32 | user.register=yes
33 | user.unregister=yes
34 | engine.timer=yes
35 | call.route=yes
36 | ;...
37 |
38 | [default]
39 | priority=50
40 | account=default
41 |
42 | [user.auth]
43 | query=SELECT password FROM users WHERE username='${username}' AND password IS NOT NULL AND password<>'' AND type='user' LIMIT 1
44 | result=password
45 |
46 | [user.register]
47 | query=UPDATE users SET location='${data}',expires=NOW() + INTERVAL ${expires} SECOND,oconnection_id='${oconnection_id}' WHERE username='${username}' AND type='user' LIMIT 1
48 |
49 | [user.unregister]
50 | query=UPDATE users SET location=NULL,expires=NULL,oconnection_id=NULL WHERE expires IS NOT NULL AND username='${username}' AND type='user' LIMIT 1
51 |
52 | [engine.timer]
53 | query=UPDATE users SET location=NULL,expires=NULL,oconnection_id=NULL WHERE expires IS NOT NULL AND expires<=CURRENT_TIMESTAMP AND type='user'
54 |
55 | [call.route]
56 | query=SELECT location,(CASE WHEN location IS NULL THEN 'offline' ELSE NULL END) AS error,oconnection_id FROM users WHERE username='${called}' LIMIT 1
57 | result=location
58 | priority=120
59 |
60 | ;...
61 | ```
62 |
63 | Priorities have to be set according to your configuration. I like to have regexroute:100 and register:120 for call.route. This way it is easy to simply {\em return} in regexroute and let register handle the routing.
64 |
65 | The field `oconnection_id` is needed for Yate to map incoming calls to open TCP and TLS connections. SIP over UDP should work just fine without this field.
66 |
67 | Tables were created like this:
68 |
69 | ```SQL
70 | -- create Mysql user
71 | CREATE USER 'yate'@'localhost' IDENTIFIED BY 'mypassword';
72 | CREATE DATABASE yate;
73 | GRANT DELETE, INSERT, SELECT, USAGE, UPDATE ON yate.* TO 'yate'@'localhost';
74 | FLUSH PRIVILEGES;
75 |
76 | use yate;
77 |
78 | CREATE TABLE users (
79 | username VARCHAR(128) UNIQUE,
80 | `password` VARCHAR(128),
81 | inuse INTEGER,
82 | `location` VARCHAR(1024),
83 | expires TIMESTAMP NULL DEFAULT NULL,
84 | `type` VARCHAR(20) NULL DEFAULT NULL,
85 | oconnection_id varchar(1024) null default null);
86 | ```
87 |
--------------------------------------------------------------------------------
/70-audio.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Audio
4 | permalink: /audio/
5 | ---
6 |
7 | ## Converting Audio for Yate
8 |
9 | Despite its name, the *wave* module (as in `wave/play/...`) does not actually support wave files. It can however process raw 8kHz single channel signed-integer PCM audio data. And this is how to create such files:
10 |
11 | sox sound.wav -t raw -r 8000 -c 1 -e signed-integer sound.slin
12 |
13 | I like to wrap things in shell scripts for simple reuse:
14 | `wav2slin.sh:`
15 |
16 | ```sh
17 | #!/bin/sh
18 | sox $1 -t raw -r 8000 -c 1 -e signed-integer $2
19 | ```
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | # Site settings
2 | title: BeF's Yate Cookbook
3 | baseurl: "/yate-cookbook" # the subpath of your site, e.g. /blog/
4 | projecturl: "https://bef.github.com/yate-cookbook"
5 | github_project: bef/yate-cookbook
6 |
7 | # Build settings
8 | markdown: redcarpet
9 | highlighter: pygments
10 |
--------------------------------------------------------------------------------
/_includes/footer.html:
--------------------------------------------------------------------------------
1 |
56 |
--------------------------------------------------------------------------------
/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/_includes/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |