2008年11月30日 星期日

static/dynamic library, "file" comman usage

Refer from https://www.cs.utk.edu/help/doku.php?id=compile:c

Compile Phase:

# gcc -c hello.c

Dynamic Linking:

# gcc -o hello hello.o
# ls -lh hello
-rwx------ 1 user group 12K Sep 18 18:35 hello
# file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.2.0, dynamically linked (uses shared libs), not stripped

Static Linking:

# gcc -static -o hello hello.o
# ls -lh hello
# -rwx------ 1 user group 465K Sep 18 18:38 hello
# file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.2.0, statically linked, not stripped

2008年11月27日 星期四

How to interpret the tcpdump header

15:19:03.018317 IP (tos 0x0, ttl 63, id 27496, offset 0, flags [DF], proto TCP (6), length 62) 140.113.102.165.44298 > 192.168.2.107.46877: P, cksum 0x0180 (correct), 1:11(10) ack 12 win 365
0x0000: 4500 003e 6b68 4000 3f06 1a28 8c71 66a5 E..>kh@.?..(.qf.
0x0010: c0a8 026b ad0a b71d 6183 1a2f 7d66 3155 ...k....a../}f1U
0x0020: 8018 016d 0180 0000 0101 080a 8c57 7f5a ...m.........W.Z
0x0030: a044 62e7 6865 6c6c 6f77 6f72 6c64 .Db.helloworld

15:19:03.018317 ==> timestamp
IP (tos 0x0, ttl 63, id 27496, offset 0, flags [DF], proto TCP (6), length 62)
==> ip header
tos 0x0 ==> tos value 0x0
ttl 63 ==> ttl value is 63
id 27496==> ip id is 27496
offset 0 ==> offset is 0
flags [DF] ==> IP flag don't flagment
proto TCP (6) ==> trasnport protocol is tcp (6)
length 62) ==> ip length is 62 (include ip header)

140.113.102.165.44298 > 192.168.2.107.46877
==> source ip/port from 140.113.102.165.44298 to destination ip/port 192.168.2.107.46877

: P, cksum 0x0180 (correct), 1:11(10) ack 12 win 365
:P ==> TCP flag, PUSH flag is on, ACK will not show, S indicate SYN, F indicate FIN, R indicate RST
cksum 0x0180 (correct) ==> tcp check sum is 0x0180, validate it is correct
1:11(10) ==> sequence number diff is from 1:11 total 10 bytes
ack 12 ==> the data had been received is 12-1 bytes, next expected bytes is 12th byte
win 365 ==>
The sender can receive max data size next time.

0101 080a 8c57 7f5a a044 62e7
01 => no operation, nop
01 => no operation, nop
08 => timestamp
0a => 10 bytes (in the tomestamp option, 8 bytes for data)
8c57 7f5a => Timestamp value, 2354544474
a044 62e7 => Timestamp echo reply, 2688836327






2008年11月20日 星期四

Linux Command - fdisk, File system management

>> partition the hard drive, list all the partition tables
# fdisk -l

>> Enter specified partions, press p to display all the partions
# fdisk /dev/sda

Disk /dev/sda: 8589 MB, 8589934592 bytes
255 heads, 63 sectors/track, 1044 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x000dda97

Device Boot Start End Blocks Id System
/dev/sda1 * 1 25 200781 83 Linux
/dev/sda2 26 1044 8185117+ 8e Linux LVM ==> LVM is a Linux Volumn Manager, Can support RAID architecture

>> format the file system
# mke2fs

>> physically mount the file system
# mount /dev/hdc1 /vm

Linux System - File Systems.. LVM management

# ls -la /dev/rootvg/
/dev/rootvg/LogVol00 -> /dev/mapper/rootvg-LogVol00
/dev/rootvg/LogVol01 -> /dev/mapper/rootvg-LogVol01
/dev/rootvg/LogVolVM01 -> /dev/mapper/rootvg-LogVolVM01

# ls -la /dev/mapper/
total 0
control
rootvg-LogVol00
rootvg-LogVol01
rootvg-LogVolVM01

# lvdisplay /dev/rootvg/LogVol00
--- Logical volume ---
LV Name /dev/rootvg/LogVol00
VG Name rootvg
LV UUID SYotdp-V3oQ-Gc5p-wDjv-txyz-Q09p-7cgsXz
LV Write Access read/write
LV Status available
# open 1
LV Size 200.00 GB
Current LE 6400
Segments 2
Allocation inherit
Read ahead sectors 0
Block device 253:0

# lvdisplay /dev/rootvg/LogVol01
--- Logical volume ---
LV Name /dev/rootvg/LogVol01
VG Name rootvg
LV UUID 8MT67X-WpcY-Nyw3-MA57-jKKn-ryq6-9dMWcD
LV Write Access read/write
LV Status available
# open 1
LV Size 1.94 GB
Current LE 62
Segments 1
Allocation inherit
Read ahead sectors 0
Block device 253:1

# lvdisplay /dev/rootvg/LogVolVM01
--- Logical volume ---
LV Name /dev/rootvg/LogVolVM01
VG Name rootvg
LV UUID e9LYTF-yFRz-RdC1-KC8q-wAN1-2UiM-8dILP5
LV Write Access read/write
LV Status available
# open 0
LV Size 50.00 GB
Current LE 1600
Segments 1
Allocation inherit
Read ahead sectors 0
Block device 253:2


How to enlarge an exsiting partition, here is my experience.
1. First umount the file system
# umount /vm

2. Then use lvextend to extend the logical volumn to the specified volumn size
# lvextend -L80G /dev/rootvg/LogVolVM01

3. Then run the e2fsck to check the new file system
# e2fsck -f /dev/rootvg/LogVolVM01

4. Use resize2fs to reorgnize the new logical volumn
# resize2fs /dev/rootvg/LogVolVM01

5. mount the logical volumn to the file sytem
# mount /dev/rootvg/LogVolVM01 /vm

http://www.kume.idv.tw/read-226.html

首先,我要說明一下。我用的是Fedora Code 5。所以我以下所用到的指令,全部都有。不需要download 與build任何東西。

第一件事就是載入LVM所需要的module
% modprobe dm-mod ==> 我的不work, 可能是沒有module

接著就是找出partiton中的VG(Volume Group),以我的狀況為例,我將硬碟以usb連接到電腦後,由dmesg可以知道有 /dev/sda1, /dev/sda2兩個patitons,在以 fdisk -l /dev/sda 可以知道/dev/sda2是LVM格式。接著,我就執行:
% pvscan ==> Fedora Rescue disc 沒有包含這個程式
PV /dev/sda2 VG VolGroup00 lvm2 [18.50 GB / 32.00 MB free]
Total: 1 [18.50 GB] / in use: 1 [18.50 GB] / in no VG: 0 [0 ]

從以上結果,我可以知道我有一個VG,叫做VolGroup00,他的PV(Physical Volume)是 /dev/sda2

接著我就執行:
% vgchange -ay VolGroup00 ==>我測試是不用加VolGroup00 參數, 只要% cgchange -ay 就會在/dev/ 下面產生一個VolGroup00 folder, 並且在這個目錄下產生該有的device(其實是link到/dev /mapper下)。
% ls /dev/VolGroup00/
LogVol00 LogVol01

這時候vgchange會在/dev下產生一個VolGroup00的目錄,並且在這個目錄下產生該有的device(其實是link到/dev /mapper下)。然後我利用 ls就可以知道VolGroup00這個VG下有兩個LV(Logical Volume)。分別是LogVol00 與 LogVol01。然後我只要mount我要的就可以了。
% mkdir /mnt/usb
% mount /dev/VolGroup00/LogVol00 /mnt/usb/ ==> 在/dev/VolGroup00/ folder下面會有兩個file, 分別表示LVM的2個檔案, 包含有 /dev/VolGroup00/LogVol00, /dev/VolGroup00/LogVol01, 這裡的例子是將第一個LVM mount 到/mnt/usb 這個logic folder 下, 然後就可以直接存取 /mnt/usb 這個路徑去抓LVM 1的data了


Q. How to rescue the HD with LVM file system?
A.
1. Insert the Fedora disc 1, enter rescue mode.
2. Issue the following commands to find the LVM partitions
# lvm vgscan
# lvm vgchange -ay
# lvm lvs

// e2fsck -y==>all questions response "yes", -c==>fix bad block file system
# e2fsck -y -c /dev/VolGroup00/LogVol00
# e2fsck -y -c /dev/VolGroup00/LogVol01

2008年11月18日 星期二

kamailio doesn't forward the ACK

UAC
1. Receive 200 OK
SIP/2.0 200 OK
| INFO3 | cb_rcv2xx (id=2)^M
| INFO1 | cb_nict_kill_transaction (id=2)^M
| INFO4 | sipevent evt: method called!

2. Send ACK

3. Receive 200 OK again
| INFO1 | 2xx restransmission receveid.^M
| INFO1 | Message sent:
4. Send ACK again
| INFO1 | ACK restransmission sent.

2008年11月17日 星期一

SIP Register with authentication required (using eXosip2)

->Send Register

->Receive SIP/2.0 407 Proxy Authentication Required with header
Proxy-Authenticate: Digest realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX"

->Send Register with header
Proxy-Authorization: Digest username="XXXXX", realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX", uri="sip:W.X.Y.Z", response="ZZZZe5d430141e984ff50fa560bWWWW", algorithm=MD5 ==>1st try

->Receive SIP/2.0 407 Proxy Authentication Required with header
Proxy-Authenticate: Digest realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX"

->Send Register with header
Proxy-Authorization: Digest username="XXXXX", realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX", uri="sip:W.X.Y.Z", response="ZZZZe5d430141e984ff50fa560bWWWW", algorithm=MD5 ==>2nd try

->Receive SIP/2.0 407 Proxy Authentication Required with header
Proxy-Authenticate: Digest realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX"

->Send Register with header
Proxy-Authorization: Digest username="XXXXX", realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX", uri="sip:W.X.Y.Z", response="ZZZZe5d430141e984ff50fa560bWWWW", algorithm=MD5 ==>3rd try

->Receive SIP/2.0 407 Proxy Authentication Required with header
Proxy-Authenticate: Digest realm="W.X.Y.Z", nonce="YYYY0992000000046dd64e657218e5a77472ae059c69XXXX"

2008年11月16日 星期日

echo/warning/error messages in the bash shell

Reference from the kamailio source, scripts/kamdbctl.base
mdbg() {
if [ "0$VERBOSE" -ne 0 ] ; then
if [ -t 1 -a -z "$NOHLPRINT" ] ; then
echo -e "\033[1m$1\033[0m"
else
echo "$1"
fi
fi
}

mwarn() {
if [ -t 1 -a -z "$NOHLPRINT" ] ; then
echo -e '\E[37;32m'"\033[1mWARNING: $1\033[0m"
else
echo "** WARNING: $1"
fi
}

minfo() {
if [ -t 1 -a -z "$NOHLPRINT" ] ; then
echo -e '\E[37;33m'"\033[1mINFO: $1\033[0m"
else
echo "** INFO: $1"
fi
}

mecho() {
if [ -t 1 -a -z "$NOHLPRINT" ] ; then
echo -e "\033[1m$1\033[0m"
else
echo "$1"
fi
}

merr() {
if [ -t 1 -a -z "$NOHLPRINT" ] ; then
echo -e '\E[37;31m'"\033[1mERROR: $1\033[0m"
else
echo "** ERROR: $1"
fi
}

Show the mysql information

# /usr/bin/mysqladmin version
Server version 5.0.45
Protocol version 10
Connection Localhost via UNIX socket
UNIX socket /var/lib/mysql/mysql.sock
Uptime: 13 sec

Threads: 1 Questions: 1 Slow queries: 0 Opens: 12 Flush tables: 1 Open tables: 6 Queries per second avg: 0.077

PS. Sometimes mysqladmin find the wrong socket (althought that socket is specified in the /etc/my.conf)

In this case we must specify the mysql socket
# mysqladmin -S /var/lib/mysql/mysql.sock version

Or we can modify the config file /etc/my.cnf

/etc/my.cnf is list below
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

[client] ==> Add this two lines to make all the mysql* client command can read correct path of mysql domain socket file
socket=/var/lib/mysql/mysql.sock


>> Show all the mysql database
# /usr/bin/mysqlshow
+-------------------- +
| Databases |
+-------------------- +
| information_schema |
| mysql |
| test |
+--------------------+

>> Show all the tables of a specified mysql database (mysql)
# mysqlshow mysql

2008年11月12日 星期三

ICMP Redirect real experience

Sometimes the source host send a packet to a router(usually default gateway) that is originally can route by the source host itself. And doesn't need the help of the router, then the router will probably send the "icmp redirect" packet to inform the source host (if the router support and enable the feature).

The following is my experience

Network topology
Source host(A/Ma)---------
|
|------Default Gateway (G/Mg)
|
Destination host(B/Mb)----

The source host (A), MAC address is Ma, and destination host (B), MAC address is Mb, is in the same subnet which all connect to the default gateway (G), MAC address is Mg.

If the A want to send a packet to the B, the packet in theory must be A/Ma-->B/Mb,
but cause of some reason, the packet become A/Ma-->B/Mg (the routing table of A is wrong, the A fill the wrong MAC address ....).

So the packet was sent to the default gateway G because of the destination MAC is Mg. And G will according the destination address of packet to lookup the routing table of the G and determine that this packet should not send to the G. Because of the source host A can send the packet directly and no need to send the packet to the G for the routing help. So the G will generate a icmp redirect packet to inform the source host this situation.

The icmp redirect packet is like following

Type: 5 (Redirect)
Code: 1 (Redirect for host)
Gateway address: B (B)
The remaining is the original packet data include ip, transport udp/tcp, app

And then the source host A will resend the packet with A/Mg-->B/Mb. And the packet will correctly send to the destination host B for processing.

In the further packets, the source host A still send the packet to the default gateway (with destination MAC address Mg). And this packet will drop by the M. But the source host will "automatically" send the correct packet to the destination B with MAC address Mb without the default gateway G sending the icmp redirect packet to inform source host A.

Every period time, the default gateway will send the icmp redirect packet to inform the source host A the wrong destination MAC addreess if the default gateway still receive the MAC-confused packet. I think that Default gateway doesn't send the icmp redirect packet each time most because of that this may be a DoS attack. So the Gateway must sensitive to response the icmp redirect packet to avoid system too busy to operate the normal tasks.

2008年11月9日 星期日

kamctl usage

usr/local/sbin/kamctl

Existing commands:

-- command 'start|stop|restart'

restart ............................ restart Kamailio
start .............................. start Kamailio
stop ............................... stop Kamailio

-- command 'acl' - manage access control lists (acl)

acl show [] .............. show user membership
acl grant ....... grant user membership (*)
acl revoke [] .... grant user membership(s) (*)

-- command 'lcr' - manage least cost routes (lcr)

* IP addresses must be entered in dotted quad format e.g. 1.2.3.4 *
* and must be entered in integer or text,*
* e.g. transport '2' is identical to transport 'tcp'. *
* scheme: 1=sip, 2=sips; transport: 1=udp, 2=tcp, 3=tls *
* Examples: lcr addgw level3 1.2.3.4 5080 sip tcp 1 *
* lcr addroute +1 '' 1 1 *
lcr show .....................................................................
............. show routes, gateways and groups
lcr reload ...................................................................
............. reload lcr gateways
lcr addgw
............... add a gateway with flags, tag and strip ............
................(flags, tag, and strip are optional arguments) .....
lcr rmgw ..........................................................
............... delete a gateway
lcr addroute .................................
.............. add a route ( use '' to match anything in )
lcr rmroute .................................
.............. delete a route

-- command 'cr' - manage carrierroute tables

cr show ....................................................... show tables
cr reload ..................................................... reload tables
cr dump ....................................................... show in memory tables
cr addrt ..................... add a tree
cr rmrt ....................................... rm a tree
cr addcarrier ................
...............
.........................add a carrier
(prob, strip, rewrite_prefix, rewrite_suffix,...................
flags, mask and comment are optional arguments) ...............
cr rmcarrier ................ rm a carrier

-- command 'rpid' - manage Remote-Party-ID (RPID)

rpid add ......... add rpid for a user (*)
rpid rm ................. set rpid to NULL for a user (*)
rpid show ............... show rpid of a user

-- command 'add|passwd|rm' - manage subscribers

add .......... add a new subscriber (*)
passwd ......... change user's password (*)
rm ...................... delete a user (*)

-- command 'add|dump|reload|rm|show' - manage trusted

trusted show ...................... show db content
trusted dump ...................... show cache content
trusted reload .................... reload db table into cache
trusted add
....................... add a new entry
....................... (from_pattern and tag are optional arguments)
trusted rm ............... remove all entres for the given src_ip

-- command 'dispatcher' - manage dispatcher

* Examples: dispatcher addgw 1 sip:1.2.3.1:5050 1 'outbound gateway'
* dispatcher addgw 2 sip:1.2.3.4:5050 3 ''
* dispatcher rmgw 4
dispatcher show ..................... show dispatcher gateways
dispatcher reload ................... reload dispatcher gateways

dispatcher dump ..................... show in memory dispatcher gateways
dispatcher addgw
.......................... add gateway
dispatcher rmgw ................ delete gateway

-- command 'db' - database operations

db exec ..................... execute SQL query
db roexec ................. execute read-only SQL query
db run ......................... execute SQL query from $id variable
db rorun ....................... execute read-only SQL query from
$id variable
db show ..................... display table content

-- command 'speeddial' - manage speed dials (short numbers)

speeddial show ....... show speeddial details
speeddial list ............. list speeddial for uri
speeddial add [] ...
........................... add a speedial (*)
speeddial rm ....... remove a speeddial (*)
speeddial help ...................... help message
- , must be an AoR (username@domain)
- must be an AoR (username@domain)
- must be a SIP AoR (sip:username@domain)
- a description for speeddial

-- command 'avp' - manage AVPs

avp list [-T table] [-u ]
[-a attribute] [-v value] [-t type] ... list AVPs
avp add [-T table]
............ add AVP (*)
avp rm [-T table] [-u ]
[-a attribute] [-v value] [-t type] ... remove AVP (*)
avp help .................................. help message
- -T - table name
- -u - SIP id or unique id
- -a - AVP name
- -v - AVP value
- -t - AVP name and type (0 (str:str), 1 (str:int),
2 (int:str), 3 (int:int))
- must be an AoR (username@domain)
- must be a string but not AoR

-- command 'alias_db' - manage database aliases

alias_db show .............. show alias details
alias_db list ............. list aliases for uri
alias_db add ...... add an alias (*)
alias_db rm ................ remove an alias (*)
alias_db help ...................... help message
- must be an AoR (username@domain)"
- must be an AoR (username@domain)"

-- command 'domain' - manage local domains

domain reload ....................... reload domains from disk
domain show ......................... show current domains in memory
domain showdb ....................... show domains in the database
domain add ................. add the domain to the database
domain rm .................. delete the domain from the database

Modify kamailo config to make Contact attribute become aware (public ip address)

The client_nat_test/fix_contact had been moved to the nat_traversal module (they are locarted mediaproxy module before v1.3(include))

Just modify the route block inside the /usr/local/etc/kamailio/kamailo.cfg

if (is_method("REGISTER"))
{
# My adding part
if (client_nat_test("3")) {
fix_contact();
}


if (!save("location"))
sl_reply_error();

exit;
}
#Another you can add the nat_keepalive like following
if ((is_method("REGISTER") || is_method("SUBSCRIBE") || is_method("INVITE") && !has_totag()) && client_nat_test("3"))
{
nat_keepalive();
}




Reference: nat traversal module document (v1.4), some snapshots..
1.5.1. client_nat_test(type)

Check if the client is behind NAT. What tests are performed is specified by the type parameter which is an integer given by the sum of the numbers corresponsing to the tests that one wishes to perform. The numbers corresponding to individual tests are shown below:

*

1 - tests if client has a private IP address (as defined by RFC1918) in the Contact field of the SIP message.
*

2 - tests if client has contacted Kamailio from an address that is different from the one in the Via field. Both the IP and port are compared by this test.
*

4 - tests if client has a private IP address (as defined by RFC1918) in the top Via field of the SIP message.

For example calling client_nat_test("3") will perform test 1 and test 2 and return true if at least one succeeds, otherwise false.

This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.

Example 1.6. Using the client_nat_test function

...
if (client_nat_test("3")) {
.....
}
...



1.5.2. fix_contact()

Will replace the IP and port in the Contact header with the IP and port the SIP message was received from. Usually called after a succesful call to client_nat_test(type)

This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE.

Example 1.7. Using the fix_contact function

...
if (client_nat_test("3")) {
fix_contact();
}
...



1.5.3. nat_keepalive()

Trigger keepalive functionality for the source address of the request. When called it only sets some internal flags, which will trigger later the addition of the endpoint to the keepalive list if a positive reply is generated/received (for REGISTER and SUBSCRIBE) or when the dialog is started/replied (for INVITEs). For this reason, it can be called early or late in the script. The only condition is to call it before replying to the request or before sending it to another proxy. If the request needs to be sent to another proxy, t_relay() must be used to be able to intercept replies via TM or dialog callbacks. If stateless forwarding is used, the keepalive functionality will not work. Also for outgoing INVITEs, record_route() should also be used to make sure the proxy that keeps the caller endpoint alive stays in the path. For multi-proxy setups, this function should always be called on the border proxies (the ones that received the request directly from the user agent). For more details about this function, see the Implementation subsection from the Keepalive functionality section.

This function can be used from REQUEST_ROUTE.

Example 1.8. Using the nat_keepalive function

...
if ((method=="REGISTER" || method=="SUBSCRIBE" ||
(method=="INVITE" && !has_totag())) && client_nat_test("3"))
{
nat_keepalive();
}
...

SIP attribute meaning

Contact is the location where UA can receive the message from the SIP Server (Registrar)
Contact:

Original from sip-ua the contact is private address, like the following describes
Contact:

After the openser processing, it will modify to the public one (e.g. 1.2.3.4)
Contact: ;expires=240

2008年11月7日 星期五

How to Configure OpenSER: SIP Registar, SIP Proxy and Far-End NAT Traversal for Media

http://www.jeremy-mcnamara.com/2007/03/28/how-to-configure-openser-sip-registar-sip-proxy-and-far-end-nat-traversal-for-media/

OpenSER is a flexible, mature and stable SIP communications server. However unlike Asterisk, OpenSER requires extensive knowledge of the SIP Protocol and presumes nothing about your configuration or method of deployment.
I am basing this configuration on OpenSER v1.1.1 which is currently considered the most 'stable' version. Although v1.2 has been released, I am going to let others find and kill the lingering bugs before diving in myself.
This configuration will utilize the necessary modules and configuration directives of OpenSER to create a SIP Registrar, conditionally detect and route based on the dialed URI (digits). Plus we will overcome most NAT situations that many home and small business level deployments will encounter, using the MediaProxy option. (The other option being the older RTPProxy method)
The IP Address for this configuration will be 1.2.3.4, of course you will need to replace this with your own IP address. You also must setup an instance of MySQL and allow OpenSER to communicate with it (MySQL can very easily run on the same machine) I will use 'openser' as the username and 'valid_pass' as the password.
Once you have MySQL running you need to find the 'mysqldb.sh' script located in the scripts directory inside of the OpenSER v1.1.1 tarball.
This will create the 'openser' database, tables and required initial data.
proxy:# sh ./mysqldb.sh create
Next copy the file 'openserctl.mysql' from the scripts directory into /usr/local/lib/openser/openserctl/ directory
proxy:# cp openserctl.mysql /usr/local/lib/openser/openserctl/
The OpenSER make install process should do this for you, but as of v1.1.1 this did not happen for me.
Finally we can dive into the configuration of OpenSER. The default OpenSER configuration file is /usr/local/etc/openser/openser.cfg
Lets dive right in.
openser.cfg:
debug=3
fork=no
log_stderror=yes
Those three options set the stage for how OpenSER will act and function. By not forking and logging to STDERR one can run openser directly to gather information about an invalid configuration directive or perhaps why a specific module isn't loading as expected. However to start OpenSER using openserctl you will need to set fork=yes and log_stderror=no.
listen=1.2.3.4
alias=1.2.3.4
port=5060
The next 3 inform OpenSER which interface and tcp/dup ports to listen on. Pretty standard stuff, so far.
children=4
The children directive informs OpenSER of how many 'child' threads to keep around to process incoming messages. 4 seems to be a reasonable default for most systems. If you really start to scale up your OpenSER instance you will want to bump this value up, but remember each additional thread takes more memory so there is somewhat of a trade off - performance versus memory usage.
dns=no
rev_dns=no
Disabling the looking up up DNS is the most scalable option. Only enable the looking up of DNS if you really need it. In fact, I haven't found a really good reason for OpenSER to need to know about DNS names.
fifo="/tmp/openser_fifo"
fifo_db_url="mysql://openser:valid_pass@localhost/openser"
Those define the FIFOs that OpenSER will use to communicate on. Remember to provide valid database information.
loadmodule "/usr/local/lib/openser/modules/mysql.so"
loadmodule "/usr/local/lib/openser/modules/sl.so"
loadmodule "/usr/local/lib/openser/modules/tm.so"
loadmodule "/usr/local/lib/openser/modules/rr.so"
loadmodule "/usr/local/lib/openser/modules/maxfwd.so"
loadmodule "/usr/local/lib/openser/modules/usrloc.so"
loadmodule "/usr/local/lib/openser/modules/registrar.so"
loadmodule "/usr/local/lib/openser/modules/auth.so"
loadmodule "/usr/local/lib/openser/modules/auth_db.so"
loadmodule "/usr/local/lib/openser/modules/uri.so"
loadmodule "/usr/local/lib/openser/modules/uri_db.so"
loadmodule "/usr/local/lib/openser/modules/mediaproxy.so"
loadmodule "/usr/local/lib/openser/modules/nathelper.so"
loadmodule "/usr/local/lib/openser/modules/textops.so"
loadmodule "/usr/local/lib/openser/modules/domain.so"
loadmodule "/usr/local/lib/openser/modules/xlog.so"
loadmodule "/usr/local/lib/openser/modules/uac.so"
loadmodule "/usr/local/lib/openser/modules/speeddial.so"
loadmodule "/usr/local/lib/openser/modules/avpops.so"
The loading of the necessary modules is the meat and potatos for this configuration of OpenSER. I won't go into the specifics of each module here as the OpenSER team has done an excellent job of documenting the modules.
modparam("usrloc|auth_db|domain|speeddial|acc", "db_url", "mysql://openser:valid_pass@localhost/openser")
modparam("auth_db", "calculate_ha1", 1)
modparam("auth_db", "use_domain", 0)
modparam("domain", "db_mode", 1)
modparam("nathelper", "rtpproxy_disable", 1)
modparam("nathelper", "natping_interval", 60)
modparam("mediaproxy","natping_interval", 30)
modparam("mediaproxy","mediaproxy_socket", "/var/run/mediaproxy.sock")
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "use_domain", 0)
modparam("registrar", "default_expires", 60)
modparam("registrar", "min_expires", 30)
modparam("registrar", "nat_flag", 6)
modparam("registrar", "use_domain", 0)
modparam("rr", "enable_full_lr", 1)
modparam("auth", "rpid_suffix", ";party=calling;id-type=subscriber;screen=yes")
modparam("auth", "rpid_avp", "s:rpid")
Same goes for the modparams - The OpenSER team has documented these quite nicely. I will point out that we disable the rtpproxy, enable mediaproxy, enable write-through database mode for the user location, enable full loose routing support (to appease broken SIP User Agents), and setup a few 'flags' for logging, accounting and NAT.
Flags are a fun concept - Generally speaking a flag in OpenSER is like sticking a PostIT? Note on to specific SIP messages. Then later on in the 'route' processing we can check to see if specific notes have been left, making for much cleaner and simpler configuration.
Now we get into the "main" section of the configuration. In the OpenSER configuration everything is ran through a route block - meaning every SIP message gets processed thru a block of code named route (or you can think about it as a 'main' function, if you are a programmer)
route {
# Sanity Check
# ------------
if (msg:len > max_len) {
sl_send_reply("513", "Message Overflow");
return;;
};

if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483", "Too Many Hops");
return;
};
The first two directives in our route block ensure we don't process a message that is too large (buffer overflow) or a message that we believe to be looping or otherwise confused.
# Record Route and NAT Preset
# --------------------
if (method == "INVITE" && client_nat_test("3")) {
# Must add valid IP address below
record_route_preset("1.2.3.4:5060;nat=yes");
} else if (method != "REGISTER") {
record_route();
};
The 'if' directive here checks to see if the current SIP message (in OpenSER terms this is called a 'method') is an INVITE and calls a function to determine if the entity sending the current SIP message is behind NAT or not. The '3′ instructs the function to test using the first two test methods, which are detailed on the NATHELPER module. If both of those conditions are true, we call a function that appends a small bit of information to the SIP message, which we will utilize later on in the route and its related blocks.
Then If the method is not a REGISTER, we setup the necessary SIP headers to ensure that further SIP messages come back through our SIP Proxy, by calling the record_route() function.
# Call Tear down
if (method=="BYE" || method=="CANCEL") {
end_media_session();
};
Then a call get hung up, we need to detect this to ensure our RTP MediaProxy gets informed to stop relaying audio. We also set our first flag. In this case we inform the accounting module that we would like to account for Bye and Cancel methods - meaning we want 'stop' Call Detail Records. Since we defined '1′ as our accounting flag, we simply pass a '1′ to the setflag() function - Pretty simple. The accounting module takes care of everything else for us.
# Loose Route
# -----------
if (loose_route()) {
if (has_totag() && (method == "INVITE" || method == "ACK")) {
if (client_nat_test("3") || search("^Route:.*;nat=yes")) {
setflag(6);
use_media_proxy();
};
};
route(1);
return;
};
This is a rather complex and powerful group of directives. Without getting into the gory details of the SIP Protocol, this block determines if we are using the 'loose routing' concept. If so, we need to check for NAT (possibly setting flag 6) and informing the MediaProxy we will need its services. Most often than not we will be using the loose routing conventions versus strict routing, as defined in RFC3261.
We also call route(1) - In our configuration this is what we call the 'default' route or the terminating route. We will document the implementation and usage of route(1) here in a few minutes.
# Call Type Processing
# --------------------
if (uri != myself) {
route(1);
return;
};
If the 'call' is no longer for this particular proxy - send the message on its way (via the 'default' route). This is sort of another sanity check for our simple configuration. However in more complex situations, examining the URI and properly routing the messages will become very important. Unfortunately those concepts are beyond the scope of this document.
if (uri == myself) {
if (method == "BYE") {
route(4);
return;
} else if (method == "CANCEL") {
route(4);
return;
} else if (method == "INVITE") {
route(3);
return;
} else if (method == "REGISTER") {
route(2);
return;
} else if (method == "NOTIFY") {
sl_send_reply("200", "Understood");
return;
} else if (method == "OPTIONS") {
sl_send_reply("200", "Got it");
return;
}
};
route(1);
}
Finally we reach the end of our route block. We test each SIP method type and send them to an appropriate 'route' blocks, with the exceptions being NOTIFY and OPTIONS methods. These two methods typcially get used (by Asterisk and many SIP Phones) to either assist in keeping firewall/NAT paths open and/or determining if the proxy is still allve or not. Asterisk can also calculate (qualify=1000) how long it takes for the message to be responded to, giving a sort of internet path health status. By processing the NOTIFY and OPTIONS methods here, we can avoid 404 and/or Too Many Hops message, which in themselves are not necessarily a bad thing, but could lead to confusion.
# Default Message Handling
# -----------------------
route[1] {
t_on_reply("1");
if (!t_relay()) {
if (method=="INVITE" || method=="ACK") {
end_media_session();
};
sl_reply_error();
};
}
Now we are down to the specific route blocks. As we discussed above, route[1] is the default message route. Here we ensure the SIP message gets properly responded to or sent on to its intended location, if the message is intended for another SIP Proxy.
We also check to see if we are processing an INVITE or ACK (to an invite) so we can inform the MediaProxy to end its session.
# REGISTER Message Handling
# -------------------------
route[2] {
if (!search("^Contact:\ +\*") && client_nat_test("7")) {
setflag(6);
fix_nated_register();
force_rport();
};
sl_send_reply("100", "Trying");
if (!www_authorize("","subscriber")) {
www_challenge("","0");
return;
};
if (!check_to()) {
sl_send_reply("401", "Unauthorized");
return;
};
consume_credentials();
if (!save("location")) {
sl_reply_error();
};
}
route[2] is our REGISTER method processing block. This is where we examine the credentials and determine if we are going to allow the SIP UA to register or not.
Notice the call to consume_credentials(), this is a very useful function that removes the unnecessary SIP headers that can contain sensitive authentication details.
# INVITE Message Handling
# ----------------------------------
route[3] {
# Test for nat, perhaps fix headers
if (client_nat_test("3")) {
setflag(7);
force_rport();
fix_nated_contact();
};

# 3 and 4 digits URIs are sent to our Asterisk PBX
if ((uri =~ "^sip:[0-9]{3}@.*") || (uri =~ "^sip:[0-9]{4}@.*")) {
rewritehost("pbx.valid.host.com:5060");
use_media_proxy();
route(1);
return;
};

# Any URI that begins with 1 plus 10 digits authenticate and pass on
# to our SIP Provider
if (uri =~ "^sip:1[0-9]{10}@.*") {
# Authenticate these calls
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0?);
return;
} else if (!check_from()) {
sl_send_reply("403?, "Use From ID");
return;
};
consume_credentials();
rewritehostport("proxy-1.nufone.net:5060?);
route(1);
return;
};

if (!lookup("location")) {
sl_send_reply("404?, "User Not Found, Sorry");
return;
};

# If NAT is previously detected, proxy
if (isflagset(6) || isflagset(7)) {
use_media_proxy();
};

route(1);
}
route[3] is our INVITE (or call setup) processing occurs. I have set this configuration up to match on 3 and 4 digit 'extensions' to send them to our Asterisk PBX. Then match on 1+10 digits to send off to our VoIP Provider, making sure to set the accounting flag (1) so we can get proper 'start' Call Detail Records.
# CANCEL and BYE Message Handling
# ----------------------------------
route[4] {
if (client_nat_test("3")) {
setflag(7);
force_rport();
fix_nated_contact();
};
end_media_session();
route(1);

}
route[4] is pretty straight forward - If its a CANCEL or BYE Message, ensure the message gets sent back to the proper location (ip:port). Then inform the MediaProxy to stop processing audio, since the call is ending.
onreply_route[1] {
if ((isflagset(6) || isflagset(7)) && (status=~"(180)|(183)|2[0-9][0-9]")) {
if (!search("^Content-Length:\ +0")) {
use_media_proxy();
};
};
if (client_nat_test("1")) {
fix_nated_contact();
};
}
The onreply_route[1] block gets called when we are expected to reply to a message (like a progress message or an OK). We ensure the MediaProxy gets used if NAT has been previously set or detected and the Contact SIP header is properly 'fixed' for NAT situations.
There you have it. This by far is NOT a comprehensive guide to configuring OpenSER, but I hope it gives you a deeper understanding of the power that we have available to us. Be sure to checkout the OpenSER Configuration Wizard, which provides an more complex configuration situations.
OpenSER is a magical and wonderful Open Source project that has and will continue to power many VoIP Providers and forward thinking enterprises for years to come.
I need your help. I am part of a team that is putting together OpenSER and Asterisk training material. If you have any questions or would like something specific covered, please take 2 minutes and fill out my OpenSER and Asterisk Training Questionnaire.



Related Posts:
VoIP Blog
OpenSER vs SER
Run Your Own SIP Server, Today!
SER/OpenSER Configuration Wizard
Multiple Via Headers in SIP messages
This entry was posted on Wednesday, March 28th, 2007 at 9:05 pm and is filed under How To, OpenSER, VoIP. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
6 Responses to "How to Configure OpenSER: SIP Registar, SIP Proxy and Far-End NAT Traversal for Media"
1. Configuration file for OpenSER v1.2.x to do VoIP NAT traversal using RTPProxy. - Voxilla VoIP Forum on June 28th, 2007 at 2:07 pm
[…] located. Send in the last few lines of that output if you are still confused. Also, check out my OpenSER How To. It may help you understand things a little bit […]
2. Run Your Own SIP Server, Today! by Jeremy McNamara on July 21st, 2007 at 11:27 pm
[…] Unlike Asterisk, OpenSER only deals with the SIP Signaling. This focus allows for a very high levels of scale and flexibility of configuration. Be sure to check out my OpenSER HowTo and check out the OpenSER Wizard, which generates very powerful configurations for multiple situations. […]
3. OpenSER vs SER by Jeremy McNamara on September 7th, 2007 at 10:59 pm
[…] there are two different variations of the same basic platform. I have previously published an OpenSER tutorial however there is another SIP server called […]
4. Blackeye1010 on November 27th, 2007 at 4:24 pm
Hello,
Your handling of sip methods, send BYE and CANCEL to a route block of theyr own. I'm using a config derived from the onsip site. At this link http://siprouter.onsip.org/doc/gettingstarted/ch08.html#mp_handle_cancel
is stated that:
"We now explicitly handle CANCEL messages. CANCEL messages can be safely processed with a simple call to t_relay() because SER will automatically match the CANCEL message to the original INVITE message. So here we just route the message to the default message handler."
…so i'm sending my BYES and CANCELS to the generalist route[1].
Would you say it's better or worse ? Or did you do that because Openser behaves diferent in this case ?
Regards
5. George on May 13th, 2008 at 6:58 pm
You keep talking about setting the accounting flag to '1′ but I don't see it anywhere
6. katiamong on June 1st, 2008 at 5:36 am
hi jeremy, i had a problem in forwarding INVITE message to asterisk.
i've tried with basic authentification with mysql anda forwarding it to asterisk if there a call to ext 701 (just example). i've always got message 'loop detected" and i try many solution it still happen.
Later i try using your configuration using media proxy, i've got problem with authetification (when sosftphone is registering the number, it says forbidden).
is there a solution how to make it works ?
i'm sorry to interupt you but you say in your blog that you need a lot of FAQ, and have no idea where i could post my question in your blog.

2008年11月5日 星期三

httrack - web site copier

Some examples
httrack www.someweb.com/bob/
mirror site www.someweb.com/bob/ and only this site
==> The above command is work for me. But for some web site (http://samba.org/ftp/unpacked/junkcode/), it will not able to get the data from that site. Until now I don't know the real reason.


httrack www.someweb.com/bob/ www.anothertest.com/mike/ +*.com/*.jpg -mime:application/*
mirror the two sites together (with shared links) and accept any .jpg files on .com
sites

httrack www.someweb.com/bob/bobby.html +* -r6
means get all files starting from bobby.html, with 6 link-depth, and possibility of
going everywhere on the web

httrack www.someweb.com/bob/bobby.html --spider -P proxy.myhost.com:8080
runs the spider on www.someweb.com/bob/bobby.html using a proxy

httrack --update
updates a mirror in the current folder

httrack
will bring you to the interactive mode

httrack --continue
continues a mirror in the current folder

Some hints in the C programming

1. Before using the character strings (either char array or malloc buffer), it is better to clean up all the buffer to zero (using memset(buf, 0, bufsize) or bzero function)

Question:
Sometimes we use the following declaration

char *mystr;

Then we can assign a string to the variable "mystr", like this. Is it valid to use this method?
mystr = "hello world";