diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3ed4cb1149..1d177ef2ef 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -209,6 +209,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define SIPBUFSIZE 512 +/* Arguments for find_peer */ +#define FINDALLDEVICES FALSE +#define FINDONLYUSERS TRUE + #define XMIT_ERROR -2 #define SIP_RESERVED ";/?:@&=+$,# " @@ -1690,15 +1694,18 @@ static int peer_ipcmp_cb(void *obj, void *arg, int flags) { struct sip_peer *peer = obj, *peer2 = arg; - if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr) + if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr) { return 0; + } if (!ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) && !ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) { - if (peer->addr.sin_port == peer2->addr.sin_port) + if (peer->addr.sin_port == peer2->addr.sin_port) { return CMP_MATCH | CMP_STOP; - else + } else { return 0; + } } + return CMP_MATCH | CMP_STOP; } @@ -4080,6 +4087,31 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i return peer; } +struct peer_finding_info { + struct sip_peer tmp_peer; + int forcenamematch; +}; + +/* Function to assist finding peers by name only */ +static int find_by_name(void *obj, void *arg, int flags) +{ + struct sip_peer *search = obj; + struct peer_finding_info *pfi = arg; + + /* Usernames in SIP uri's are case sensitive. Domains are not */ + if (strcmp(search->name, pfi->tmp_peer.name)) { + return 0; + } + + /* If we're only looking for name matches, we should avoid type=peer devices, + since these should not match on any name-based search */ + if (pfi->forcenamematch && search->onlymatchonip) { + return 0; + } + + return CMP_MATCH | CMP_STOP; +} + /*! \brief Locate device by name or ip address * This is used on find matching device on name or ip/port. If the device was declared as type=peer, we don't match on peer name on incoming INVITEs. @@ -4090,12 +4122,13 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int forcenamematch, int devstate_only) { struct sip_peer *p = NULL; - struct sip_peer tmp_peer; - + if (peer) { - ast_copy_string(tmp_peer.name, peer, sizeof(tmp_peer.name)); - p = ao2_t_find(peers, &tmp_peer, OBJ_POINTER, "ao2_find in peers table"); + struct peer_finding_info pfi = { .forcenamematch = forcenamematch, }; + ast_copy_string(pfi.tmp_peer.name, peer, sizeof(pfi.tmp_peer.name)); + p = ao2_t_callback(peers, OBJ_POINTER, find_by_name, &pfi, "ao2_callback in peers table"); } else if (sin) { /* search by addr? */ + struct sip_peer tmp_peer; tmp_peer.addr.sin_addr.s_addr = sin->sin_addr.s_addr; tmp_peer.addr.sin_port = sin->sin_port; tmp_peer.flags[0].flags = 0; @@ -4359,7 +4392,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd dialog->sa.sin_family = AF_INET; dialog->timer_t1 = global_t1; /* Default SIP retransmission timer T1 (RFC 3261) */ dialog->timer_b = global_timer_b; /* Default SIP transaction timer B (RFC 3261) */ - peer = find_peer(peername, NULL, TRUE, TRUE, FALSE); + peer = find_peer(peername, NULL, TRUE, FINDALLDEVICES, FALSE); if (peer) { int res; @@ -4714,7 +4747,7 @@ static int update_call_counter(struct sip_pvt *fup, int event) ast_copy_string(name, fup->username, sizeof(name)); /* Check the list of devices */ - if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, TRUE, FALSE, FALSE) ) ) { /* Try to find peer */ + if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, TRUE, FINDALLDEVICES, FALSE) ) ) { /* Try to find peer */ inuse = &p->inUse; call_limit = &p->call_limit; inringing = &p->inRinging; @@ -10892,7 +10925,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request * /*! \brief Change onhold state of a peer using a pvt structure */ static void sip_peer_hold(struct sip_pvt *p, int hold) { - struct sip_peer *peer = find_peer(p->peername, NULL, 1, TRUE, FALSE); + struct sip_peer *peer = find_peer(p->peername, NULL, 1, FINDALLDEVICES, FALSE); if (!peer) return; @@ -11041,7 +11074,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr ast_string_field_set(p, exten, name); build_contact(p); - peer = find_peer(name, NULL, TRUE, TRUE, FALSE); + peer = find_peer(name, NULL, TRUE, FINDALLDEVICES, FALSE); if (!(peer && ast_apply_ha(peer->ha, sin))) { /* Peer fails ACL check */ if (peer) { @@ -11912,7 +11945,7 @@ static void replace_cid(struct sip_pvt *p, const char *rpid_num, const char *cal } } -/*! \brief Validate peer authentication */ +/*! \brief Validate device authentication */ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, struct sip_request *req, int sipmethod, struct sockaddr_in *sin, struct sip_peer **authpeer, @@ -11923,10 +11956,20 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, int debug=sip_debug_test_addr(sin); struct sip_peer *peer; - /* For subscribes, match on device name only; for other methods, - * match on IP address-port of the incoming request. - */ - peer = (sipmethod == SIP_SUBSCRIBE) ? find_peer(of, NULL, TRUE, FALSE, FALSE) : find_peer(NULL, &p->recv, TRUE, FALSE, FALSE); + if (sipmethod == SIP_SUBSCRIBE) { + /* For subscribes, match on device name only; for other methods, + * match on IP address-port of the incoming request. + */ + peer = find_peer(of, NULL, TRUE, FINDALLDEVICES, FALSE); + } else { + /* First find devices based on username (avoid all type=peer's) */ + peer = find_peer(of, NULL, TRUE, FINDONLYUSERS, FALSE); + + /* Then find devices based on IP */ + if (!peer) { + peer = find_peer(NULL, &p->recv, TRUE, FINDALLDEVICES, FALSE); + } + } if (!peer) { if (debug) @@ -13175,7 +13218,7 @@ static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const str return CLI_SHOWUSAGE; load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE; - if ((peer = find_peer(argv[3], NULL, load_realtime, FALSE, FALSE))) { + if ((peer = find_peer(argv[3], NULL, load_realtime, FINDALLDEVICES, FALSE))) { sip_poke_peer(peer, 1); unref_peer(peer, "qualify: done with peer"); } else if (type == 0) { @@ -13257,7 +13300,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct return CLI_SHOWUSAGE; load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE; - peer = find_peer(argv[3], NULL, load_realtime, TRUE, FALSE); + peer = find_peer(argv[3], NULL, load_realtime, FINDALLDEVICES, FALSE); if (s) { /* Manager */ if (peer) { const char *id = astman_get_header(m, "ActionID"); @@ -13578,7 +13621,7 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg if (a->argc != 3) return CLI_SHOWUSAGE; - if ((peer = find_peer(a->argv[2], NULL, load_realtime, TRUE, TRUE))) { + if ((peer = find_peer(a->argv[2], NULL, load_realtime, FINDALLDEVICES, TRUE))) { if (peer->expire > 0) { expire_register(ref_peer(peer, "ref for expire_register")); ast_cli(a->fd, "Unregistered peer \'%s\'\n\n", a->argv[2]); @@ -14550,7 +14593,7 @@ static char *sip_do_debug_ip(int fd, char *arg) /*! \brief Turn on SIP debugging for a given peer */ static char *sip_do_debug_peer(int fd, char *arg) { - struct sip_peer *peer = find_peer(arg, NULL, TRUE, TRUE, FALSE); + struct sip_peer *peer = find_peer(arg, NULL, TRUE, FINDALLDEVICES, FALSE); if (!peer) ast_cli(fd, "No such peer '%s'\n", arg); else if (peer->addr.sin_addr.s_addr == 0) @@ -15046,7 +15089,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat else colname = "ip"; - if (!(peer = find_peer(data, NULL, TRUE, TRUE, FALSE))) + if (!(peer = find_peer(data, NULL, TRUE, FINDALLDEVICES, FALSE))) return -1; if (!strcasecmp(colname, "ip")) { @@ -17374,9 +17417,12 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); return 0; } else { - /* This is a spiral. What we need to do is to just change the outgoing INVITE + /*! This is a spiral. What we need to do is to just change the outgoing INVITE * so that it now routes to the new Request URI. Since we created the INVITE ourselves * that should be all we need to do. + * + * \todo XXX This needs to be reviewed. YOu don't change the request URI really, you route the packet + * correctly instead... */ char *uri = ast_strdupa(req->rlPart2); char *at = strchr(uri, '@'); @@ -20111,7 +20157,7 @@ int st_get_se(struct sip_pvt *p, int max) if (p->stimer->st_cached_max_se) { return p->stimer->st_cached_max_se; } else if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, TRUE, FALSE); + struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, FINDALLDEVICES, FALSE); if (pp) { p->stimer->st_cached_max_se = pp->stimer.st_max_se; unref_peer(pp, "unref peer pointer from find_peer call in st_get_se"); @@ -20124,7 +20170,7 @@ int st_get_se(struct sip_pvt *p, int max) if (p->stimer->st_cached_min_se) { return p->stimer->st_cached_min_se; } else if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, TRUE, FALSE); + struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, FINDALLDEVICES, FALSE); if (pp) { p->stimer->st_cached_min_se = pp->stimer.st_min_se; unref_peer(pp, "unref peer pointer from find_peer call in st_get_se (2)"); @@ -20146,7 +20192,7 @@ enum st_refresher st_get_refresher(struct sip_pvt *p) return p->stimer->st_cached_ref; if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, TRUE, FALSE); + struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, FINDALLDEVICES, FALSE); if (pp) { p->stimer->st_cached_ref = pp->stimer.st_ref; unref_peer(pp, "unref peer pointer from find_peer call in st_get_refresher"); @@ -20171,7 +20217,7 @@ enum st_mode st_get_mode(struct sip_pvt *p) return p->stimer->st_cached_mode; if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, TRUE, FALSE); + struct sip_peer *pp = find_peer(p->peername, NULL, TRUE, FINDALLDEVICES, FALSE); if (pp) { p->stimer->st_cached_mode = pp->stimer.st_mode_oper; unref_peer(pp, "unref peer pointer from find_peer call in st_get_mode"); @@ -20358,7 +20404,7 @@ static int sip_devicestate(void *data) * load it BACK into memory, thus defeating the point of trying to clear dead * hosts out of memory. */ - if ((p = find_peer(host, NULL, FALSE, TRUE, TRUE))) { + if ((p = find_peer(host, NULL, FALSE, FINDALLDEVICES, TRUE))) { if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) { /* we have an address for the peer */ @@ -22147,7 +22193,7 @@ static int reload_config(enum channelreloadreason reason) if (!strcasecmp(utype, "user")) { is_peer = 1; } else if (!strcasecmp(utype, "friend")) { - is_peer = 2; + is_peer = 1; } else if (!strcasecmp(utype, "peer")) is_peer = 2; else {