diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-09-10 22:31:20 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-09-10 22:31:20 +0000 |
commit | a833bd5cc7471ae5ae9567b8e7409cd5e3393029 (patch) | |
tree | 5f257dd63e5ec30f114367b806931f8a58bfb02e /channels | |
parent | 877f6dcd88a2af696eaa6bb26c4e04a2ebe3520d (diff) |
sip peer matching by address only with TCP/TLS
This patch removes the contact header matching logic and
adds logic to match all tcp/tls connections by ip only.
Thanks to oej for finding the issue and suggesting solutions.
Review: https://reviewboard.asterisk.org/r/355/
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@217913 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 82 |
1 files changed, 41 insertions, 41 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5695620e0..02cadad55 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1832,7 +1832,7 @@ static int reload_config(enum channelreloadreason reason); static int expire_register(const void *data); static void *do_monitor(void *data); static int restart_monitor(void); -static int sip_addrcmp(char *name, struct sockaddr_in *sin); /* Support for peer matching */ +static int sip_addrcmp(char *name, struct sip_peer *p2); /* Support for peer matching */ static int sip_refer_allocate(struct sip_pvt *p); static void ast_quiet_chan(struct ast_channel *chan); static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target); @@ -1951,7 +1951,7 @@ static int sip_poke_peer(struct sip_peer *peer); static void set_peer_defaults(struct sip_peer *peer); static struct sip_peer *temp_peer(const char *name); static void register_peer_exten(struct sip_peer *peer, int onoff); -static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only); +static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only, int transport); static struct sip_user *find_user(const char *name, int realtime); static int sip_poke_peer_s(const void *data); static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req); @@ -4041,13 +4041,21 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i } /*! \brief Support routine for find_peer */ -static int sip_addrcmp(char *name, struct sockaddr_in *sin) +static int sip_addrcmp(char *name, struct sip_peer *p2) { /* We know name is the first field, so we can cast */ struct sip_peer *p = (struct sip_peer *) name; - return !(!inaddrcmp(&p->addr, sin) || - (ast_test_flag(&p->flags[0], SIP_INSECURE_PORT) && - (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr))); + char tcptls = (p->transports & p2->transports) & (SIP_TRANSPORT_TLS | SIP_TRANSPORT_TCP); + + /* first check to see if it is a perfect ip port match. + * if not, check to see if it valid for the peer to be matched only by ip */ + if (!inaddrcmp(&p->addr, &p2->addr)) { + return 0; + } else if ((tcptls || ast_test_flag(&p->flags[0], SIP_INSECURE_PORT)) && (p->addr.sin_addr.s_addr == p2->addr.sin_addr.s_addr)) { + return 0; + } + + return 1; } /*! \brief Locate peer by name or ip address @@ -4056,14 +4064,21 @@ static int sip_addrcmp(char *name, struct sockaddr_in *sin) \note Avoid using this function in new functions if there's a way to avoid it, i since it causes a database lookup or a traversal of the in-memory peer list. */ -static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only) +static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only, int transport) { struct sip_peer *p = NULL; + struct sip_peer tmp_peer; - if (peer) + if (peer) { p = ASTOBJ_CONTAINER_FIND(&peerl, peer); - else - p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); + } else { + 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; + tmp_peer.transports = transport; + + p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, &tmp_peer, name, sip_addr_hashfunc, 1, sip_addrcmp); + } if (!p && realtime) p = realtime_peer(peer, sin, devstate_only); @@ -4386,7 +4401,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, int newdialog) 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, 1, 0); + peer = find_peer(peername, NULL, 1, 0, 0); if (peer) { int res; @@ -4732,7 +4747,7 @@ static int update_call_counter(struct sip_pvt *fup, int event) call_limit = &u->call_limit; inringing = NULL; pu_lock = &u->_lock; - } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1, 0) ) ) { /* Try to find peer */ + } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1, 0, 0) ) ) { /* Try to find peer */ inuse = &p->inUse; call_limit = &p->call_limit; inringing = &p->inRinging; @@ -9918,7 +9933,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname); if (!ast_strlen_zero(r->peername)) { - if (!(peer = find_peer(r->peername, NULL, 1, 0))) { + if (!(peer = find_peer(r->peername, NULL, 1, 0, 0))) { ast_log(LOG_WARNING, "Could not find peer %s in transmit_register\n", r->peername); } } @@ -10974,7 +10989,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, 0); + struct sip_peer *peer = find_peer(p->peername, NULL, 1, 0, 0); if (!peer) return; @@ -11208,7 +11223,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, 1, 0); + peer = find_peer(name, NULL, 1, 0, 0); if (!(peer && ast_apply_ha(peer->ha, sin))) { /* Peer fails ACL check */ if (peer) { @@ -12200,23 +12215,8 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, /* For subscribes, match on peer name only; for other methods, * match on IP address-port of the incoming request. */ - peer = (sipmethod == SIP_SUBSCRIBE) ? find_peer(of, NULL, 1, 0) : find_peer(NULL, &p->recv, 1, 0); - - /* If the peer is still not found, try the address and port from the - * contact header. If the transport type is TCP or TLS it is not possible - * to find the peer using p->recv. Because of the way TCP works, the received - * packet's destination port will not match the one the peer table is - * built with. */ - if (!peer && (p->socket.type != SIP_TRANSPORT_UDP)) { - struct sockaddr_in tmpsin; - char contact[SIPBUFSIZE]; - char *tmp; - memcpy(&tmpsin, &p->recv, sizeof(tmpsin)); - ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); - tmp = get_in_brackets(contact); - __set_address_from_contact(tmp, &tmpsin, 1); - peer = find_peer(NULL, &tmpsin, 1, 0); - } + peer = (sipmethod == SIP_SUBSCRIBE) ? find_peer(of, NULL, 1, 0, 0) : find_peer(NULL, &p->recv, 1, 0, p->socket.type); + if (!peer) { if (debug) ast_verbose("No matching peer for '%s' from '%s:%d'\n", @@ -13431,7 +13431,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, 0); + peer = find_peer(argv[3], NULL, load_realtime, 0, 0); if (s) { /* Manager */ if (peer) { const char *id = astman_get_header(m, "ActionID"); @@ -13786,7 +13786,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, 0))) { + if ((peer = find_peer(a->argv[2], NULL, load_realtime, 0, 0))) { if (peer->expire > 0) { AST_SCHED_DEL(sched, peer->expire); expire_register(peer); @@ -14674,7 +14674,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, 1, 0); + struct sip_peer *peer = find_peer(arg, NULL, 1, 0, 0); if (!peer) ast_cli(fd, "No such peer '%s'\n", arg); else if (peer->addr.sin_addr.s_addr == 0) @@ -15173,7 +15173,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat else colname = "ip"; - if (!(peer = find_peer(data, NULL, 1, 0))) + if (!(peer = find_peer(data, NULL, 1, 0, 0))) return -1; if (!strcasecmp(colname, "ip")) { @@ -20227,7 +20227,7 @@ int st_get_se(struct sip_pvt *p, int max) } } if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0); + struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0, 0); if (pp) { p->stimer->st_cached_max_se = pp->stimer.st_max_se; unref_peer(pp); @@ -20250,7 +20250,7 @@ int st_get_se(struct sip_pvt *p, int max) } } if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0); + struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0, 0); if (pp) { p->stimer->st_cached_min_se = pp->stimer.st_min_se; unref_peer(pp); @@ -20281,7 +20281,7 @@ enum st_refresher st_get_refresher(struct sip_pvt *p) } if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0); + struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0, 0); if (pp) { p->stimer->st_cached_ref = pp->stimer.st_ref; return pp->stimer.st_ref; @@ -20313,7 +20313,7 @@ enum st_mode st_get_mode(struct sip_pvt *p) } } if (p->peername) { - struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0); + struct sip_peer *pp = find_peer(p->peername, NULL, 1, 0, 0); if (pp) { p->stimer->st_cached_mode = pp->stimer.st_mode_oper; unref_peer(pp); @@ -20474,7 +20474,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, 0, 1))) { + if ((p = find_peer(host, NULL, 0, 1, 0))) { if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) { /* we have an address for the peer */ |