Created
May 31, 2013 15:22
-
-
Save oogali/5685713 to your computer and use it in GitHub Desktop.
Testing SIP INVITEs -- I think I used this to prank Vonage users w/ATA-186s back in the day
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <md5.h> | |
#define WWW_AUTH 1 | |
#define PROXY_AUTH 2 | |
#define ACK 10 | |
#define OK 11 | |
#define CANCEL 12 | |
extern int errno; | |
extern int h_errno; | |
char *our_ip, *our_username, *our_realm, *our_passwd, our_host[256], current_method[64]; | |
int our_port, cseq, pktstatus, our_uid; | |
long callid, tag; | |
void process_pktstatus(char *incoming, int incominglen) | |
{ | |
char tmp[4]; | |
int i, offset; | |
offset = 8; | |
i = offset; | |
while (((incoming[i] != ' ') && (i != incominglen))) { | |
tmp[i - offset] = incoming[i]; | |
i++; | |
} | |
tmp[i - offset] = '\0'; | |
pktstatus = atoi(tmp); | |
printf("Got a SIP 2.0 packet with a status code of %d\n\n\n", pktstatus); | |
} | |
int process_message(char *incoming, int incominglen) | |
{ | |
int i, offset; | |
char from[512], to[512], dest[512], msg[2048]; | |
char *ptr; | |
offset = 8; | |
i = offset; | |
while(((incoming[i] != ' ') && (i != incominglen))) { | |
dest[i - offset] = incoming[i]; | |
i++; | |
} | |
dest[i - offset] = '\0'; | |
ptr = strstr(incoming, "From:"); | |
if (ptr == NULL) { | |
printf("Could not find From: in packet\n"); | |
} else { | |
offset = 6; | |
i = offset; | |
while(((ptr[i] != '\r') && (i != incominglen))) { | |
from[i - offset] = ptr[i]; | |
i++; | |
} | |
from[i - offset] = '\0'; | |
} | |
ptr = strstr(incoming, "To:"); | |
if (ptr == NULL) { | |
printf("Could not find To: in packet\n"); | |
} else { | |
offset = 4; | |
i = offset; | |
while(((ptr[i] != '\r') && (i != incominglen))) { | |
to[i - offset] = ptr[i]; | |
i++; | |
} | |
to[i - offset] = '\0'; | |
} | |
ptr = strstr(incoming, "\r\n\r\n"); | |
if (ptr == NULL) { | |
printf("Could not find start of message in packet\n"); | |
} else { | |
offset = 4; | |
i = offset; | |
while(i != incominglen && i != (sizeof(msg) - 1)) { | |
msg[i - offset] = ptr[i]; | |
i++; | |
} | |
msg[i - offset] = '\0'; | |
} | |
if (from && to && dest && msg) { | |
printf("Message sent from %s to %s (%s):\n", from, to, dest); | |
printf("%s\n", msg); | |
return 0; | |
} else { | |
return -1; | |
} | |
} | |
int send_pkt(int s, char *pkt, struct sockaddr_in sin) | |
{ | |
int len, slen; | |
len = strlen(pkt); | |
slen = sendto(s, pkt, len, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)); | |
if (slen != len) { | |
perror("sendto"); | |
exit(-1); | |
} | |
printf("Sent %d bytes to %s:%d\n", slen, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); | |
printf("%s\n", pkt); | |
return(slen); | |
} | |
void send_reply(int s, char *incoming, int incominglen, struct sockaddr_in sin, int reply, char *method) | |
{ | |
char rcvd_callid[256], *pkt, from[256], *ptr, contact[256], to[256], via[4096], tmp[255], tmp2[8]; | |
int i, j, k, offset, vias = 0; | |
ptr = strstr(incoming, "Via:"); | |
if (ptr == NULL) { | |
printf("Could not find Via: in packet\n"); | |
} else { | |
i = 0; | |
j = 0; | |
while (i != incominglen) { | |
if (ptr[i] == 'V' && ptr[i + 1] == 'i' && ptr[i + 2] == 'a' && ptr[i + 3] == ':') { | |
while(ptr[i] != '\r') { | |
via[j] = ptr[i]; | |
i++; | |
j++; | |
} | |
vias++; | |
via[j] = '\0'; | |
if (vias == 1) { | |
offset = 17; | |
k = offset; | |
while((via[k] != ';' && via[k] != ':' && via[k] != '\r') && ((k - offset) < sizeof(tmp))) { | |
tmp[k - offset] = via[k]; | |
k++; | |
} | |
if (strcmp(tmp, our_host) == 0 && strcmp(tmp, our_ip) == 0) { | |
tmp[k - offset] = '\0'; | |
sin.sin_addr.s_addr = inet_addr(tmp); | |
offset = k; | |
if (via[k] == ':') { | |
k++; offset++; | |
while(via[k] != ';' && via[k] != '\r') { | |
tmp2[k - offset] = via[k]; | |
k++; | |
} | |
sin.sin_port = htons(atoi(tmp2)); | |
} | |
} | |
strncat(via, ";received=", sizeof(via)); | |
strncat(via, our_ip, sizeof(via)); | |
j += strlen(";received=") + strlen(our_ip); | |
} | |
via[j] = '\r'; | |
j++; | |
via[j] = '\n'; | |
j++; | |
} | |
i++; | |
} | |
via[j - 2] = '\0'; | |
} | |
ptr = strstr(incoming, "From:"); | |
if (ptr == NULL) { | |
printf("Could not find From: in packet\n"); | |
} else { | |
offset = 6; | |
i = offset; | |
while(((ptr[i] != '\r') && (i != incominglen))) { | |
from[i - offset] = ptr[i]; | |
i++; | |
} | |
from[i - offset] = '\0'; | |
} | |
ptr = strstr(incoming, "To:"); | |
if (ptr == NULL) { | |
printf("Could not find To: in packet\n"); | |
} else { | |
offset = 4; | |
i = offset; | |
while(((ptr[i] != '\r') && (i != incominglen))) { | |
to[i - offset] = ptr[i]; | |
i++; | |
} | |
to[i - offset] = '\0'; | |
} | |
ptr = strstr(incoming, "Contact:"); | |
if (ptr == NULL) { | |
printf("Could not find Contact: in packet\n"); | |
} else { | |
offset = 9; | |
i = offset; | |
while(((ptr[i] != '\r') && (i != incominglen))) { | |
contact[i - offset] = ptr[i]; | |
i++; | |
} | |
contact[i - offset] = '\0'; | |
} | |
ptr = strstr(incoming, "Call-ID:"); | |
if (ptr != NULL) { | |
offset = 9; | |
i = offset; | |
while(incoming[i] != '\r' && i != incominglen) { | |
rcvd_callid[i - offset] = ptr[i]; | |
i++; | |
} | |
rcvd_callid[i - offset] = '\0'; | |
} else { | |
snprintf(rcvd_callid, sizeof(rcvd_callid), "%d@%s", callid, our_host); | |
} | |
if (from && rcvd_callid) { | |
switch(reply) { | |
case ACK: | |
asprintf(&pkt, "ACK sip:%d@%s SIP/2.0\nVia: SIP/2.0/UDP %s:%d\nFrom: %s\nTo: %s\nContact: %s\nCall-Id: %s\nCSeq: %d %s\n\n", our_uid, our_ip, our_ip, our_port, from, to, contact, rcvd_callid, cseq, method); | |
break; | |
case OK: | |
asprintf(&pkt, "SIP/2.0 200 OK\n%s\nFrom: %s\nTo: %s;tag=%ld\nContact: %d@%s\nCall-Id: %s\nCSeq: %d %s\nContent-Length: 0\n\n", via, from, to, tag, our_uid, our_ip, rcvd_callid, cseq, method); | |
break; | |
case CANCEL: | |
asprintf(&pkt, "CANCEL %s SIP/2.0\nVia: SIP/2.0/UDP %s:%d\nFrom: %s\nTo: %s;tag=%ld\nContact: %d@%s\nCall-Id: %s\nCSeq: %d %s\nContent-Length: 0\n\n", to, our_host, our_port, from, to, tag, our_uid, our_ip, rcvd_callid, cseq, method); | |
break; | |
default: | |
printf("Unknown reply packet specified.\n"); | |
break; | |
} | |
if (pkt != NULL) { | |
send_pkt(s, pkt, sin); | |
free(pkt); | |
} | |
} | |
} | |
void get_current_cseq(char *incoming, int incominglen) | |
{ | |
int i, offset; | |
char tmp[16], *ptr; | |
ptr = strstr(incoming, "CSeq:"); | |
if (ptr != NULL) { | |
offset = 6; | |
i = offset; | |
while(ptr[i] != ' ' && i != incominglen) { | |
tmp[i - offset] = ptr[i]; | |
i++; | |
} | |
tmp[i - offset] = '\0'; | |
cseq = atoi(tmp); | |
// printf("Current CSeq is set to %d\n", cseq); | |
} | |
} | |
int recv_pkt(int s, char *incoming, int incominglen, struct sockaddr_in sin) | |
{ | |
int len, rlen; | |
len = sizeof(struct sockaddr); | |
bzero(incoming, incominglen); | |
rlen = recvfrom(s, incoming, incominglen, 0, (struct sockaddr *)&sin, &len); | |
if (rlen > 0) { | |
printf("Received %d bytes from %s:%d\n", rlen, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); | |
printf("%s\n", incoming); | |
} | |
get_current_cseq(incoming, rlen); | |
if (incoming[0] == 'S' && incoming[1] == 'I' && incoming[2] == 'P' && incoming[3] == '/' && incoming[4] == '2' && incoming[5] == '.' && incoming[6] == '0') { | |
process_pktstatus(incoming, rlen); | |
} else if (incoming[0] == 'M' && incoming[1] == 'E' && incoming[2] == 'S' && incoming[3] == 'S' && incoming[4] == 'A' && incoming[5] == 'G' && incoming[6] == 'E') { | |
if (process_message(incoming, rlen) == 0) { | |
strncpy(current_method, "MESSAGE", sizeof(current_method)); | |
send_reply(s, incoming, rlen, sin, OK, "MESSAGE"); | |
} | |
} else if (incoming[0] == 'B' && incoming[1] == 'Y' && incoming[2] == 'E') { | |
strncpy(current_method, "BYE", sizeof(current_method)); | |
send_reply(s, incoming, rlen, sin, ACK, "BYE"); | |
} | |
return(rlen); | |
} | |
int send_register(int s, struct sockaddr_in sin, char *authc, char *authz, char *incoming, int type) | |
{ | |
char *ptr, *pkt; | |
int i = 0, slen = 0, offset; | |
char realm[256], nonce[256]; | |
char stage1_md5[33], stage2_md5[33], stage3_md5[33], uri[512]; | |
MD5_CTX ctx; | |
ptr = strstr(incoming, authc); | |
if (ptr != NULL) { | |
ptr = strstr(incoming, "realm"); | |
while(ptr[i] != '"') { | |
i++; | |
} | |
i++; | |
offset = i; | |
while(ptr[i] != '"') { | |
realm[i - offset] = ptr[i]; | |
i++; | |
} | |
realm[i - offset] = '\0'; | |
i = 0; | |
ptr = strstr(incoming, "nonce"); | |
while(ptr[i] != '"') { | |
i++; | |
} | |
i++; | |
offset = i; | |
while(ptr[i] != '"') { | |
nonce[i - offset] = ptr[i]; | |
i++; | |
} | |
nonce[i - offset] = '\0'; | |
MD5Init(&ctx); | |
MD5Update(&ctx, our_username, strlen(our_username)); | |
MD5Update(&ctx, ":", 1); | |
MD5Update(&ctx, realm, strlen(realm)); | |
MD5Update(&ctx, ":", 1); | |
MD5Update(&ctx, our_passwd, strlen(our_passwd)); | |
MD5End(&ctx, stage1_md5); | |
if (type == PROXY_AUTH) | |
snprintf(uri, sizeof(uri), "sip:%s@%s", our_username, our_realm); | |
else if (type == WWW_AUTH) | |
snprintf(uri, sizeof(uri), "sip:%s", our_realm); | |
else | |
snprintf(uri, sizeof(uri), "UNKNOWNAUTHMETHOD"); | |
MD5Init(&ctx); | |
MD5Update(&ctx, current_method, strlen(current_method)); | |
MD5Update(&ctx, ":", 1); | |
MD5Update(&ctx, uri, strlen(uri)); | |
MD5End(&ctx, stage2_md5); | |
MD5Init(&ctx); | |
MD5Update(&ctx, stage1_md5, strlen(stage1_md5)); | |
MD5Update(&ctx, ":", 1); | |
MD5Update(&ctx, nonce, strlen(nonce)); | |
MD5Update(&ctx, ":", 1); | |
MD5Update(&ctx, stage2_md5, strlen(stage2_md5)); | |
MD5End(&ctx, stage3_md5); | |
cseq++; | |
asprintf(&pkt, "%s sip:%s SIP/2.0\nVia: SIP/2.0/UDP %s:%d\nFrom: sip:%s@%s\nTo: sip:%s@%s\nContact: sip:%ld@%s\nCall-Id: %ld@%s\nCSeq: %d %s\n%s: DIGEST username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"\n\n", current_method, our_realm, our_ip, our_port, our_username, our_realm, our_username, our_realm, our_uid, our_ip, callid, our_host, cseq, current_method, authz, our_username, realm, nonce, uri, stage3_md5); | |
if (pkt == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
slen = send_pkt(s, pkt, sin); | |
free(pkt); | |
} | |
return(slen); | |
} | |
int main(int argc, char **argv) | |
{ | |
struct sockaddr_in isin, osin; | |
int s; | |
char *pkt, incoming[1024]; | |
struct hostent *he; | |
if (argc != 8) { | |
printf("%s <my ip> <my port> <sip server> <sip port> <username> <realm> <password>\n", argv[0]); | |
return(-1); | |
} | |
our_uid = getuid(); | |
asprintf(&our_ip, argv[1]); | |
if (our_ip == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
our_port = atoi(argv[2]); | |
if (our_port <= 0) { | |
perror("atoi"); | |
return(-1); | |
} | |
asprintf(&our_username, argv[5]); | |
if (our_username == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
asprintf(&our_realm, argv[6]); | |
if (our_realm == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
asprintf(&our_passwd, argv[7]); | |
if (our_passwd == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
if (s < 0) { | |
perror("socket"); | |
return(-1); | |
} | |
isin.sin_family = AF_INET; | |
isin.sin_addr.s_addr = inet_addr(our_ip); | |
isin.sin_port = htons(our_port); | |
if (bind(s, (struct sockaddr *)&isin, sizeof(struct sockaddr)) != 0) { | |
perror("bind"); | |
return(-1); | |
} | |
if (inet_addr(argv[3]) == INADDR_NONE) { | |
he = gethostbyname(argv[3]); | |
if (he == NULL) { | |
herror("gethostbyname"); | |
return(-1); | |
} | |
memcpy((char *)&osin.sin_addr.s_addr, he->h_addr_list[0], he->h_length); | |
} else { | |
osin.sin_addr.s_addr = inet_addr(argv[3]); | |
} | |
osin.sin_family = AF_INET; | |
osin.sin_port = htons(atoi(argv[4])); | |
srandomdev(); | |
cseq = 1; | |
callid = random(); | |
tag = random(); | |
if (gethostname(our_host, sizeof(our_host)) != 0) { | |
perror("gethostname"); | |
return(-1); | |
} | |
asprintf(&pkt, "INVITE sip:asterisk@%s;user=phone SIP/2.0\nVia: SIP/2.0/UDP %s:%d\nFrom: sip:%s@%s\nTo: sip:asterisk@%s;user=phone\nContact: sip:%ld@%s\nCall-Id: %ld@%s\nCSeq: %d INVITE\n\n", inet_ntoa(osin.sin_addr), our_ip, our_port, our_username, our_realm, inet_ntoa(osin.sin_addr), our_uid, our_ip, callid, our_host, cseq); | |
if (pkt == NULL) { | |
perror("asprintf"); | |
return(-1); | |
} | |
strncpy(current_method, "INVITE", sizeof(current_method)); | |
send_pkt(s, pkt, osin); | |
free(pkt); | |
while(1) { | |
recv_pkt(s, incoming, sizeof(incoming), osin); | |
switch(pktstatus) { | |
case 400: | |
send_reply(s, incoming, sizeof(incoming), osin, CANCEL, current_method); | |
break; | |
case 401: | |
send_register(s, osin, "WWW-Authenticate", "Authorization", incoming, WWW_AUTH); | |
break; | |
case 407: | |
send_register(s, osin, "Proxy-Authenticate", "Proxy-Authentication", incoming, PROXY_AUTH); | |
break; | |
case 200: | |
send_reply(s, incoming, sizeof(incoming), osin, ACK, current_method); | |
break; | |
case 100: | |
default: | |
} | |
} | |
close(s); | |
free(our_realm); | |
free(our_username); | |
free(our_passwd); | |
free(our_ip); | |
return 0; | |
} |
Author
oogali
commented
May 31, 2013
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment