Git Product home page Git Product logo

sipexer's Introduction

sipexer

Modern and flexible SIP (RFC3261) command line tool.

Project URL:

Table Of Content

Overview

sipexer is a cli tool that facilitates sending SIP requests to servers. It uses a flexible template system to allow defining many parts of the SIP request via command line parameters. It has support for UDP, TCP, TLS and WebSocket transport protocols, being suitable to test modern WebRTC SIP servers.

sipexer is not a SIP cli softphone, but a tool for crafting SIP requests mainly for the purpose of testing SIP signaling routing or monitoring servers.

It is written in Go, aiming to be usable from Linux, MacOS or Windows.

The meaning of the name sipexer: randomly selected to be easy to write and pronounce, quickly after thought of it as the shortening of SIP EXEcutoR.

sipexer in action sending a SIP OPTIONS request:

SIP OPTIONS Request

Features

Among features:

  • send OPTIONS request (quick SIP ping to check if server is alive)
  • do registration and un-registration with customized expires value and contact URI
  • authentication with plain or HA1 passwords
  • set custom SIP headers
  • template system for building SIP requests
  • fields in the templates can be set via command line parameters or a JSON file
  • variables for setting field values (e.g., random number, data, time, environment variables, uuid, random string, ...)
  • simulate SIP calls at signaling layer (INVITE-wait-BYE)
  • option for late-offer SDP
  • respond to requests coming during SIP calls (e.g., OPTIONS keepalives)
  • send instant messages with SIP MESSAGE requests
  • color output mode for easier troubleshooting
  • support for many transport layers: IPv4 and IPv6, UDP, TCP, TLS and WebSocket (for WebRTC)
  • send SIP requests of any type (e.g., INFO, SUBSCRIBE, NOTIFY, ...)

Installation

Compile From Sources

First install Go. Once the Go environment is configured, clone sipexer git repository:

git clone https://github.com/miconda/sipexer

Download dependencies and build:

cd sipexer
go get ./...
go build .

The binary sipexer should be generated in the current directory.

Note: On some OS distributions, it may be required to run the go build command with CGO_ENABLED=0, like:

CGO_ENABLED=0 go build .

Download Binary Release

Binary releases for Linux, MacOS and Windows are available at:

Usage

Prototype:

sipexer [options] [target]

See sipexer -h for the command line options and arguments.

Defaults:

  • target address: sip:127.0.0.1:5060
  • SIP method: OPTIONS
  • From user: alice
  • From domain: localhost
  • To user: bob
  • To domain: localhost

Examples

Send an OPTIONS request over UDP to 127.0.0.1 and port 5060 - couple of variants:

sipexer
sipexer 127.0.0.1
sipexer 127.0.0.1 5060
sipexer udp 127.0.0.1 5060
sipexer udp:127.0.0.1:5060
sipexer sip:127.0.0.1:5060
sipexer "sip:127.0.0.1:5060;transport=udp"

Specify a different R-URI:

sipexer -ruri sip:[email protected] udp:127.0.0.1:5060

Send from UDP local port 55060:

sipexer -laddr 127.0.0.1:55060 udp:127.0.0.1:5060

Send REGISTER request with generated contact, expires as well as user and password authentication:

sipexer -register -cb -ex 600 -au alice -ap test123 udp:127.0.0.1:5060

Send REGISTER request with expires 60s, wait 20000ms (20s) and then unregister:

sipexer -register -vl 3 -co -com -ex 60 -fuser alice -cb -ap "abab..." -ha1 -sd -sw 20000 udp:127.0.0.1:5060

Set fuser field to carol:

sipexer -sd -fu "carol" udp:127.0.0.1:5060
# or 
sipexer -sd -fv "fuser:carol" udp:127.0.0.1:5060

Set fuser field to carol and tuser field to david, with R-URI user same as To-user when providing proxy address destination:

sipexer -sd -fu "carol"  -tu "david" -su udp:127.0.0.1:5060
# or
sipexer -sd -fv "fuser:carol"  -fv "tuser:david" -su udp:127.0.0.1:5060

Add extra headers:

sipexer -sd -xh "X-My-Key:abcdefgh" -xh "P-Info:xyzw" udp:127.0.0.1:5060

Send MESSAGE request with body:

sipexer -message -mb 'Hello!' -sd -su udp:127.0.0.1:5060

Send MESSAGE request with body over tcp:

sipexer -message -mb 'Hello!' -sd -su tcp:127.0.0.1:5060

Send MESSAGE request with body over tls:

sipexer -message -mb 'Hello!' -sd -su tls:127.0.0.1:5061

Send MESSAGE request with body over wss (WebSocket Secure):

sipexer -message -mb 'Hello!' -sd -su wss://server.com:8443/sip

Send INVITE request with default From user alice and To user bob:

sipexer -invite -vl 3 -co -com -sd -su udp:server.com:5060

Initiate a call from alice to bob, with user authentication providing the password in HA1 format, waiting 10000 milliseconds before sending the BYE, with higher verbosity level (3) and color printing:

sipexer -invite -vl 3 -co -com -fuser alice -tuser bob -cb -ap "4a4a4a4a4a..." -ha1 -sw 10000 -sd -su udp:server.com:5060

Target Address

The target address can be provided as last arguments to the sipexer command. It is optional, if not provided, then the SIP message is sent over UDP to 127.0.0.1 port 5060.

The format can be:

  • SIP URI (e.g., sip:[email protected]:5080;transport=tls)
  • SIP proxy socket address in format proto:host:port (e.g., tls:server.com:5061)
  • WSS URL (e.g., wss://server.com:8442/webrtc)
  • only the server hostname or IP (e.g., server.com)
  • host:port (transport protocol is set to UDP)
  • proto:host (port is set to 5060)
  • host port (transport protocol is set to UDP)
  • proto host (port is set to 5060)
  • proto host port (same as proto:host:port)

Message Template

Template Data

The message to be sent via the SIP connection is built from a template file and a fields file.

The template file can contain any any of the directives supported by Go package text/template - for more see:

Example:

{{.method}} {{.ruri}} SIP/2.0
Via: SIP/2.0/{{.viaproto}} {{.viaaddr}}{{.rport}};branch=z9hG4bKSG.{{.viabranch}}
From: {{if .fname}}"{{.fname}}" {{end}}<sip:{{if .fuser}}{{.fuser}}@{{end}}{{.fdomain}}>;tag={{.fromtag}}
To: {{if .tname}}"{{.tname}}" {{end}}<sip:{{if .tuser}}{{.tuser}}@{{end}}{{.tdomain}}>
Call-ID: {{.callid}}
CSeq: {{.cseqnum}} {{.method}}
{{if .subject}}Subject: {{.subject}}{{else}}$rmeol{{end}}
{{if .date}}Date: {{.date}}{{else}}$rmeol{{end}}
{{if .contacturi}}Contact: {{.contacturi}}{{if .contactparams}};{{.contactparams}}{{end}}{{else}}$rmeol{{end}}
{{if .expires}}Expires: {{.expires}}{{else}}$rmeol{{end}}
{{if .useragent}}User-Agent: {{.useragent}}{{else}}$rmeol{{end}}
Content-Length: 0

Example SDP body template:

v=0{{.cr}}
o={{.sdpuser}} {{.sdpsessid}} {{.sdpsessversion}} IN {{.sdpaf}} {{.localip}}{{.cr}}
s=call{{.cr}}
c=IN {{.sdpaf}} {{.localip}}{{.cr}}
t=0 0{{.cr}}
m=audio {{.sdprtpport}} RTP 0 8 101{{.cr}}
a=rtpmap:0 pcmu/8000{{.cr}}
a=rtpmap:8 pcma/8000{{.cr}}
a=rtpmap:101 telephone-event/8000{{.cr}}
a=sendrecv{{.cr}}

The internal templates can be found at the top of sipexer.go file:

Template Fields

The fields file has to contain a JSON document with the fields to be replaced in the template file. The path to the JSON file is provided via -ff or --fields-file parameters.

When the --fields-eval of -fe cli option is provided, sipexer evaluates the values of the fields in the root structure of the JSON document. That means special tokens (expressions) are replaced if the value of the field is a string matching one of the next:

  • "$cr" - replace with \r
  • "$dateansic" - replace with output of time.Now().Format(time.ANSIC)
  • "$datefull" - replace with output of time.Now().String()
  • "$daterfc1123" - replace with output of time.Now().Format(time.RFC1123)
  • "$dateunix" - replace with output of time.Now().Format(time.UnixDate)
  • "$env(name)" - replace with the value of the environment variable name
  • "$add(name)" - return the current value associate with name plus 1 (initial value is 0)
  • "$add(name,val)" - return the current value associate with name plus val (initial value is 0)
  • "$sub(name)" - return the current value associate with name minus 1 (initial value is 0)
  • "$sub(name,val)" - return the current value associate with name minus val (initial value is 0)
  • "$mul(name,val)" - return the current value associate with name multiplied with val (initial value is 1)
  • "$div(name,val)" - return the current value associate with name divided by val (initial value is 1)
  • "$dec(name)" - return the decremented value, first to return is 999999
  • "$dec(name,val)" - return the decremented value, first to return isval - 1
  • "$inc(name)" - return the incremented value, first to return is 1
  • "$inc(name,val)" - return the incremented value, first to return isval + 1
  • "$randseq" - replace with a random number from 1 to 1 000 000
  • "$rand(max)" - replace with a random number from 0 to max
  • "$rand(min,max)" - replace with a random number from min to max
  • "$randan(len)" - random alphanumeric string of length len
  • "$randan(minlen,maxlen)" - random alphanumeric string with length from minlen to maxlen
  • "$randhex(len)" - random hexadecimal string of length len
  • "$randhex(minlen,maxlen)" - random hexadecimal string with length from minlen to maxlen
  • "$randnum(len)" - random numeric string of length len
  • "$randnum(minlen,maxlen)" - random numeric string with length from minlen to maxlen
  • "$randstr(len)" - random alphabetic string of length len
  • "$randstr(minlen,maxlen)" - random alphabetic string with length from minlen to maxlen
  • "$rmeol" - remove next end of line character \n
  • "$timestamp" - replace with output of time.Now().Unix() - time stamp in seconds
  • "$timems" - replace with output of time.Now().UnixMilli() - time stamp in milliseconds
  • "$lf" - replace with \n
  • "$uuid" - replace with a UUID (universally unique identifier) value

When internal template is used, --fields-eval is turned on.

Example fields file:

{
	"method": "OPTIONS",
	"fuser": "alice",
	"fdomain": "localhost",
	"tuser": "bob",
	"tdomain": "localhost",
	"viabranch": "$uuid",
	"rport": ";rport",
	"fromtag": "$uuid",
	"totag": "",
	"callid": "$uuid",
	"cseqnum": "$randseq",
	"date": "$daterfc1123",
	"sdpuser": "sipexer",
	"sdpsessid": "$timestamp",
	"sdpsessversion": "$timestamp",
	"sdpaf": "IP4",
	"sdprtpport": "$rand(20000,40000)"
}

The internal fields data can be found at the top of sipexer.go file.

The values for fields can be also provided using --field-val or -fv cli parameter, in format name:value, for example:

sipexer --field-val="domain:openrcs.com" ...

The value provided via --field-val overwrites the value provided in the JSON fields file.

When sending out, before the template is evaluated, the following fields are also added internally and will replace the corresponding {{.name}} (e.g., {{.proto}}) in the template:

  • afver - address family version (4 or 6)
  • localaddr - local address - ip:port
  • localip - local ip
  • localport - local port
  • proto - lower(proto) (e.g., udp, tcp, ...)
  • protoup - upper(proto) (e.g., UDP, TCP, ...)
  • sdpaf - SDP address family (IP4 or IP6)
  • targetaddr - remote address - ip:port
  • targetip - remote ip
  • targetport - remote port
  • cr - \r
  • lf - \n
  • tab - \t

Alternatives

There are several alternatives that might be useful to consider:

  • sipp - SIP testing tool using XML-based scenarios
  • sipsak - SIP swiss army knife - SIP cli testing tool
  • wsctl - WebSocket cli tool with basic support for SIP
  • baresip - cli SIP softphone
  • pjsua - cli SIP softphone

License

GPLv3

Copyright: Daniel-Constantin Mierla (Asipto)

Contributions

Contributions are welcome!

Fork and do pull requests:

sipexer's People

Contributors

0oga83 avatar abalashov avatar brange avatar hnimminh avatar miconda avatar seven1240 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sipexer's Issues

Branch value in an INVITE ACK is wrong

The "branch" value in the Via header is wrong for an ACK in response to an INVITE that requires authentication
The actual value is the one of the second INVITE (with auth) instead of the first one (without auth)
To comply with RFC3261#17.1.1.3, the ACK Via header must be the same as the corresponding INVITE message
As a result, the INVITE is finally rejected
The issue comes from seDlg.FirstRequest in SIPExerDialogLoop() being modified by SIPExerProcessResponse() before sgsip.SGSIPInviteToACKString() is called to send the ACK.
A quick and dirty fix is to make a deep clone of seDlg.FirstRequest and use this copy inthe call to sgsip.SGSIPInviteToACKString() but this is definitely not how this should be fixed.

# 1st INVITE message :
INVITE bob@localhost SIP/2.0
Via: SIP/2.0/UDP 172.17.0.20:42701;rport;branch=z9hG4bKSG.3d94bc0c-c3f8-4839-8b62-36fa47808d27

# This INVITE requires auth :
SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 172.17.0.20:42701;rport=42701;branch=z9hG4bKSG.3d94bc0c-c3f8-4839-8b62-36fa47808d27

# ACK to INVITE with an incorrect branch value :
ACK bob@localhost SIP/2.0
Via: SIP/2.0/UDP 172.17.0.20:42701;rport;branch=z9hG4bKSG.35479688-1274-4aaf-b9b3-2f9bb4515ed9
#################### The branch value should be z9hG4bKSG.3d94bc0c-c3f8-4839-8b62-36fa47808d27

# 2nd INVITE with auth :
INVITE bob@localhost SIP/2.0
Via: SIP/2.0/UDP 172.17.0.20:42701;rport;branch=z9hG4bKSG.35479688-1274-4aaf-b9b3-2f9bb4515ed9

# As the ACK was not accepted, the INVITE is finally rejected :
SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 172.17.0.20:42701;rport=42701;branch=z9hG4bKSG.3d94bc0c-c3f8-4839-8b62-36fa47808d27

Digest auth interop problem with FreeSWITCH

I seem to have a digest auth interop problem with FreeSWITCH that I can't quite comprehend:

Invocation:

# ./sipexer -vl 3 -timer-t1 2000 -register -contact-uri sip:[email protected]:5060 -com -ex 120 -fuser abalashov -tuser abalashov -ha1 -au abalashov -ap xxx -sd -nagios udp:sip.evaristesys.com

The 401 challenge:

WWW-Authenticate: Digest realm="sip.evaristesys.com",nonce="634df9bc-54d5-431f-8dc7-66cb556fe12e",algorithm=MD5,qop="auth"

The full REGISTER response + challenge answer:

REGISTER sip:sip.evaristesys.com:5060 SIP/2.0
Via: SIP/2.0/UDP 172.30.106.189:55414;rport;branch=z9hG4bKSG.be1f3a00-c393-4f3b-8d31-82fe0af34011
From: <sip:[email protected]>;tag=6c5e9643-b2f8-4069-b756-9a731009cf3a
To: <sip:[email protected]>
Call-ID: 1b8fd706-ab3c-4c18-bfab-d39e7e382cd5
CSeq: 841081 REGISTER
Date: Tue, 15 Feb 2022 08:26:54 EST
Contact: <sip:[email protected]:5060>
Expires: 120
User-Agent: SIPExer v1.0.0
Content-Length: 0
Authorization: Digest username="abalashov", realm="sip.evaristesys.com", nonce="634df9bc-54d5-431f-8dc7-66cb556fe12e", uri="sip:sip.evaristesys.com:5060", cnonce="I4VYGmfe8VC9g+Li", nc=00000001, qop=auth, opaque="", algorithm=MD5, response="fae65c5bd2d12f84bbeaa467f3dc092e"

I stubbornly get a 403 Forbidden from FreeSWITCH, without explanation.

I've compared with a working REGISTER flow from a Polycom; aside from the Authorization response itself, the requests are indistinguishable.

As far as I can tell, the code does everything correctly:

       // build digest response
        cnonce := SIPExerRandomKey()
        response := SIPExerHMD5(strings.Join([]string{HA1, hparams["nonce"], "00000001", cnonce, hparams["qop"], HA2}, ":"))
        // build header body
        AuthHeader = fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=00000001, qop=%s, opaque="%s", algorithm=MD5, response="%s"`,
            username, hparams["realm"], hparams["nonce"], hparams["uri"], cnonce, hparams["qop"], hparams["opaque"], response)

Any pointers would be helpful! Thank you very much again for writing this amazing tool.

Getting write error

Hello,

I'm getting this intermittently, can't figure out why...

[error] [sipexer.go:1389] main.SIPExerSendBytes(): error writing - write udp4 172.26.210.130:50600->172.26.209.100:5060: i/o timeout

when call is answered.
This is my command:

./sipexer -invite -vl 9 -co -com \
	-fuser '+numberFrom' \
	-tuser numberTo \
	-rn numberTo \
	-cb \
	-sw 1000 -sd -timer-t1 60000 -su \
	udp:172.26.209.100:5060

retransmission

Hello, great utility!
Is there any way of controlling the retransmission time?

Thanks!

RTP support

First of all, I want to say thank you for creating sipexer, and it would be great if this can have audio support, to specific a wav file for sending audio

sipexer crashes when local address is in use

# sipexer -register -vl 3 -co -com -ex 60 -fuser alice -cb -ap "abab..." -ha1 -laddr 222.22.10.11:5060  -sd udp:111.22.11.33:5060

[debug] [sipexer.go:705] main.main(): parsed socket address argument ({Val:udp:111.22.11.33:5060 Proto:udp Addr:111.22.11.33 Port:5060 PortNo:5060 AType:4 ProtoId
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x6b8220]

goroutine 19 [running]:
main.SIPExerSendUDP({{0x7ffd4242984d, 0x16}, {0x737de1, 0x3}, {0x7ffd42429851, 0xd}, {0x7ffd4242985f, 0x4}, 0x13c4, 0x4, ...}, ...)
        /home/dmitry/build/sipexer/sipexer.go:1754 +0x360
created by main.main in goroutine 1
        /home/dmitry/build/sipexer/sipexer.go:780 +0x1836


This crash happens when some other app is already binded to 222.22.10.11:5060.

Route headers not properly reversed from RR set when RR URIs comma-separated

When using the -invite flow, a 200 OK is received by the sipexer UA with two RR hops:

Record-Route: <sip:GW_2:5060;lr=on;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;vsf=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AA-;dlgcor=ccf1.7e73;proxy_media=yes>
Record-Route: <sip:GW_1:5060;lr;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;dlgcor=ccf.8be1;fromcor=ejFwbUZxUmpUUFNBejFwbUZxU
UUFNBejFwbUZxUmpUUFM-;proxy_media=yes>

This is properly reversed in the order of the Route headers constructed in the e2e ACK / subsequent in-dialog messages:

Route: <sip:GW_1:5060;lr;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;dlgcor=ccf.8be1;fromcor=ejFwbUZxUmpUUFNBejFwbUZxUmp
FNBejFwbUZxUmpUUFM-;proxy_media=yes>
Route: <sip:GW_2:5060;lr=on;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;vsf=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-;dlgcor=ccf1.7e73;proxy_media=yes>

However, if the RR set returned is compacted into a single value...

Record-Route: <sip:GW_2:5060;lr=on;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;vsf=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AA-;dlgcor=ccf1.7e73;proxy_media=yes>, <sip:GW_1:5060;lr;ftag=37ff691d-7bf2-446b-abaa-9c09fe12deb1;dlgcor=ccf.8be1;fromcor=ejFwbUZxUmpUUFNBejFwbUZxU
UUFNBejFwbUZxUmpUUFM-;proxy_media=yes>

Then this order is imitated, rather than reversed, in the subsequent Route construction.

Using CGO_ENABLED=0 for Alpine Linux, etc.

I'm sorry that I'm not able to better define the reasoning, etc. on this, however the pre-compiled binary won't work on Alpine linux, and just compiling as indicated in the instructions doesn't work:

git clone https://github.com/miconda/sipexer
cd sipexer
go get ./...
go build .

Setting the env var CGO_ENABLED to 0 when building creates a binary that works (for me) in both the default alpine container as well
as my normal Debian distro:

CGO_ENABLED=0 go build .

Given that this works for me on both, I'm not sure if it's better to have the distributed binary and the instructions always reference this, OR to simply add a note in the installation section? Or maybe this is so obvious to someone working in Go that it's unnecessary?

sipexer IPv6

Hi @miconda

Thank you for the great tool. I'm starting to like this tool more than sipping.

I'm running into a tiny issue using Sipexer over IPv6 - Below is the error:

` $./sipexer fe80::acdb:69ff:feb5:7eaf

[error] [sipexer.go:726] main.main(): invalid destination address: fe80::acdb:69ff:feb5:7eaf
[root@ opt]# ./sipexer [fe80::acdb:69ff:feb5:7eaf]

panic: runtime error: slice bounds out of range [:1] with length 0

goroutine 1 [running]:
github.com/miconda/sipexer/sgsip.SGAddrTypeEx({0x0, 0x0})
/github/workspace/sgsip/sgsip.go:239 +0xb7
github.com/miconda/sipexer/sgsip.SGSIPParseSocketAddress({0xfff83881, 0x1b}, 0xa43bd4c)
/github/workspace/sgsip/sgsip.go:356 +0x56
main.main()
/github/workspace/sipexer.go:724 +0xeb4
[root@opt]# ./sipexer [::1]

panic: runtime error: slice bounds out of range [:1] with length 0

goroutine 1 [running]:
github.com/miconda/sipexer/sgsip.SGAddrTypeEx({0x0, 0x0})
/github/workspace/sgsip/sgsip.go:239 +0xb7
github.com/miconda/sipexer/sgsip.SGSIPParseSocketAddress({0xffd2c897, 0x5}, 0x9c3bd4c)
/github/workspace/sgsip/sgsip.go:356 +0x56
main.main()
/github/workspace/sipexer.go:724 +0xeb4

[root@t]# ./sipexer sip:[fe80::acdb:69ff:feb5:7eaf]:5060

[error] [sipexer.go:1814] main.SIPExerSendUDP(): error: dial udp6 [fe80::acdb:69ff:feb5:7eaf]:5060: connect: invalid argument
[root@ opt]# ./sipexer udp:[fe80::acdb:69ff:feb5:7eaf]:5060

[error] [sipexer.go:1814] main.SIPExerSendUDP(): error: dial udp6 [fe80::acdb:69ff:feb5:7eaf]:5060: connect: invalid argument
`

Any help would be appreciated! :)

It seems to support TLS, would love test TLS using SIPEXER

Support repeated extra-header

Thanks to @miconda for awesome tool,

I just found a minor issue with the sipexer use the map to store the extra-header via -xh, that cause for only the latest one can be processed.
Example:


[info] [sipexer.go:1260] main.SIPExerDialogLoop(): local socket address: 127.0.0.1:53256 (udp)
[info] [sipexer.go:1261] main.SIPExerDialogLoop(): local via address: 127.0.0.1:53256
[info] [sipexer.go:1262] main.SIPExerDialogLoop(): sending to udp 127.0.0.1:5060: [[---
INVITE sip:127.0.0.1:5060 SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:53256;rport;branch=z9hG4bKSG.256b7e98-b824-47ae-bac8-a2c3aadf9281
From: <sip:+9876543210@localhost>;tag=d3107dc4-7f35-481c-b58f-e351e2704027
To: <sip:alice@localhost>
Call-ID: f5ccddd4-da36-48d7-b218-63cff5cdca0c
CSeq: 275785 INVITE
Date: Wed, 25 May 2022 16:23:20 +07
User-Agent: SIPExer v1.0.0
Content-Length: 208
Diversion: <[email protected]>
Content-Type: application/sdp

v=0
o=sipexer 1653470600 1653470600 IN IP4 127.0.0.1
s=call
c=IN IP4 127.0.0.1
t=0 0
m=audio 37009 RTP 0 8 101
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:101 telephone-event/8000
a=sendrecv

[info] [sipexer.go:1264] main.SIPExerDialogLoop(): ---]]

only the [email protected] is processed. We expected that the message would be:

...
Diversion: <[email protected]>
Diversion: <[email protected]>
...

Reference:
https://datatracker.ietf.org/doc/html/rfc3261#section-7.3.1

hanging tcp connections

When running multiple tcp commands in row. at least in my endeavours, I encounter some problems with hanging tcp connection

sipexer -message -mb 'Heipa hei hoo' -laddr :5060 tcp:10.250.39.62:5060

[info] [sipexer.go:1434] main.SIPExerDialogLoop(): local socket address: 10.250.39.36:5060 (tcp)
[info] [sipexer.go:1435] main.SIPExerDialogLoop(): local via address: 10.250.39.36:5060
[info] [sipexer.go:1436] main.SIPExerDialogLoop(): sending to tcp 10.250.39.62:5060: [[---
MESSAGE sip:10.250.39.62:5060;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.250.39.36:5060;rport;branch=z9hG4bKSG.de99e435-7200-44bf-b954-4e8a7a8fdc4c
From: sip:alice@localhost;tag=a50e604c-99c4-4849-8ab2-538b6e809b9b
To: sip:bob@localhost
Call-ID: 363536fc-df2a-4c13-99c9-f09407766a8e
CSeq: 385409 MESSAGE
Date: Thu, 10 Nov 2022 14:01:12 UTC
User-Agent: SIPExer v1.0.3
Content-Length: 13
Content-Type: text/plain

Heipa hei hoo
[info] [sipexer.go:1438] main.SIPExerDialogLoop(): ---]]

[info] [sipexer.go:1489] main.SIPExerDialogLoop(): response-received: from=10.250.39.62:5060 bytes=304 data=[[---
SIP/2.0 403 Forbidden
Via: SIP/2.0/TCP 10.250.39.36:5060;rport;branch=z9hG4bKSG.de99e435-7200-44bf-b954-4e8a7a8fdc4c
To: sip:bob@localhost
From: sip:alice@localhost;tag=a50e604c-99c4-4849-8ab2-538b6e809b9b
CSeq: 385409 MESSAGE
Call-ID: 363536fc-df2a-4c13-99c9-f09407766a8e
Content-Length: 0

[info] [sipexer.go:1491] main.SIPExerDialogLoop(): ---]]

sipexer -message -mb 'Heipa hei hoo\n' -laddr :5060 tcp:10.250.39.62:5060

[error] [sipexer.go:1731] main.SIPExerSendTCP(): error: dial tcp4 :5060->10.250.39.62:5060: bind: address already in use

netstat -an | grep 10.250.39.62
tcp 0 0 10.250.39.36:5060 10.250.39.62:5060 TIME_WAIT

tested with:
go version go1.19.3 linux/amd64

on:
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian

bypass TLS

I know it's a long shot but I am wondering if there is a way currently (or it's an easy fix) to ignore TLS certifications validation.

error: x509: certificate signed by unknown authority

Scenario: I have a TLS SIP server, with self-signed certifcates. I specify the tls-certificate and tls-key in sipexer, but I still get the aforementioned error.

  1. How can I bypass this error, essentially make sipexer trust my self-signed certificate (and not bypas tls as a whole)?

Some minor things:
2) In which cases the tls-key could be useful ? Usually just the CAfile (in my case the self signed certificate) is enough but the code seems to require both.
3) specifying just the tls-certificate seems to not be an opton: again according to code, one needs to specify both tls-certificate and tls-key, but help doesn't say anything about it.
4) Help neglects to specify that both certificate and key must be in PEM format, at least according to docs here (still doesn't work though).

Retransmission of INVITE on receipt of 100 using TCP

When using TCP, sipexer seems to immediately re-transmit the INVITE upon receipt of 100 reply. This potentially results in a storm of packets. Note the lack of any wait time before retransmitting the INVITE.

           10.174.5.101:44330             10.174.5.11:5060 
         ──────────┬─────────          ──────────┬─────────
 11:27:56.826765   │           INVITE            │         
       +0.000889   │ ──────────────────────────> │         
 11:27:56.827654   │         100 Trying          │         
       +0.000728   │ <────────────────────────── │         
 11:27:56.828382   │           INVITE            │         
       +0.000100   │ ────────────────────────>>> │         
 11:27:56.828482   │         100 Trying          │         
       +0.000598   │ <<<──────────────────────── │         
 11:27:56.829080   │           INVITE            │         
       +0.000080   │ ────────────────────────>>> │         
 11:27:56.829160   │         100 Trying          │         
       +0.000506   │ <<<──────────────────────── │         
 11:27:56.829666   │           INVITE            │         
       +0.000086   │ ────────────────────────>>> │         
 11:27:56.829752   │         100 Trying          │         
       +0.000553   │ <<<──────────────────────── │         
 11:27:56.830305   │           INVITE            │         
       +0.000067   │ ────────────────────────>>> │         
 11:27:56.830372   │         100 Trying          │         
       +0.000632   │ <<<──────────────────────── │         
 11:27:56.831004   │           INVITE            │         
. . .

Tested against Kamailio 5.6, just returning a 100:

#!KAMAILIO

loadmodule "sl"

request_route {
    send_reply("100", "Trying");
    exit;
}

Using the following sipexer command:

sipexer -invite -co -com -cb -fu 15555551000 -tu 15555551234  -sd -su tcp:proxy

Resulted in over 1,300 messages (sent and received so over 650 INVITEs retransmitted) in less than one second.

Changing the target from tcp:proxy to udp:proxy gives the expected behavior - sipexer receives the 100 and waits.

Via: branch in non-200 ACK differs from Via: branch in INVITE.

When receiving a non 200 reply for an INVITE sipexer sends a response, but the branch parameter of the via header does not match the branch parameter of the INVITE.

Given this minimal Kamailio config:

#!KAMAILIO

loadmodule "tm.so"
loadmodule "sl.so"
loadmodule "pv.so"

request_route {
    if ( $rm == "ACK" ) {
        if( !t_check_trans() ) {
            exit;
        }
    }
    t_newtran();
    t_reply("404","Not Found");
}

Sending an Invite from sipexer (where kamailio resolves to the host running the kamailio.cfg above):

sipexer -invite kamailio

Has Kamailio repeatedly sending the 404 reply after sipexer sends an ACK. This appears to be due to the ACK's via: header having a different branch than the INVITE.

INVITE (minus SDP):

INVITE sip:kamailio:5060 SIP/2.0
Via: SIP/2.0/UDP 172.31.0.4:56595;rport;branch=z9hG4bKSG.f7f686a3-ce6d-45a1-95a7-42652740d210
From: <sip:alice@localhost>;tag=9dc18f12-c779-4b0e-b30e-681d0526c72e
To: <sip:bob@localhost>
Call-ID: 0418f8d8-d472-43ab-9dc2-786129278a1c
CSeq: 481768 INVITE
Date: Fri, 01 Apr 2022 16:30:13 CDT
User-Agent: SIPExer v1.0.0
Content-Length: 210
Content-Type: application/sdp

ACK:

ACK sip:kamailio:5060 SIP/2.0
Via: SIP/2.0/UDP 172.31.0.4:56595;rport;branch=z9hG4bKSG.cda7e72d-892c-4bee-ad36-cec0734d8c59
From: <sip:alice@localhost>;tag=9dc18f12-c779-4b0e-b30e-681d0526c72e
To: <sip:bob@localhost>;tag=a6a1c5f60faecf035a1ae5b6e96e979a-f254
Call-ID: 0418f8d8-d472-43ab-9dc2-786129278a1c
CSeq: 481768 ACK
Content-Length: 0

Call flow:

             172.31.0.4:56595              172.31.0.3:5060  
          ──────────┬─────────          ──────────┬─────────
  16:30:13.498783   │           INVITE            │ 
        +0.000956   │ ──────────────────────────> │ 
  16:30:13.499739   │        404 Not Found        │ 
        +0.000530   │ <────────────────────────── │ 
  16:30:13.500269   │             ACK             │ 
        +0.447913   │ ──────────────────────────> │ 
  16:30:13.948182   │        404 Not Found        │ 
        +0.999823   │ <<<──────────────────────── │ 
  16:30:14.948005   │        404 Not Found        │ 
        +2.000091   │ <<<──────────────────────── │ 
  16:30:16.948096   │        404 Not Found        │        
                    │ <<<──────────────────────── │

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.