00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00033
00034 #include "asterisk/module.h"
00035 #include "asterisk/event.h"
00036 #include "asterisk/sched.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/stun.h"
00039 #include "asterisk/netsock2.h"
00040 #include "asterisk/lock.h"
00041 #include <fcntl.h>
00042
00043 static const int DEFAULT_MONITOR_REFRESH = 30;
00044
00045 static const char stun_conf_file[] = "res_stun_monitor.conf";
00046 static struct ast_sched_thread *sched;
00047
00048 static struct {
00049 struct sockaddr_in stunaddr;
00050 struct sockaddr_in externaladdr;
00051 ast_mutex_t lock;
00052 unsigned int refresh;
00053 int stunsock;
00054 unsigned int monitor_enabled:1;
00055 unsigned int externaladdr_known:1;
00056 } args;
00057
00058 static inline void stun_close_sock(void)
00059 {
00060 if (args.stunsock != -1) {
00061 close(args.stunsock);
00062 args.stunsock = -1;
00063 memset(&args.externaladdr, 0, sizeof(args.externaladdr));
00064 args.externaladdr_known = 0;
00065 }
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075 static void stun_purge_socket(void)
00076 {
00077 int flags = fcntl(args.stunsock, F_GETFL);
00078 int res = 0;
00079 unsigned char reply_buf[1024];
00080
00081 fcntl(args.stunsock, F_SETFL, flags | O_NONBLOCK);
00082 while (res != -1) {
00083
00084 res = recv(args.stunsock, reply_buf, sizeof(reply_buf), 0);
00085 }
00086 fcntl(args.stunsock, F_SETFL, flags & ~O_NONBLOCK);
00087 }
00088
00089
00090 static int stun_monitor_request(const void *blarg)
00091 {
00092 int res;
00093 int generate_event = 0;
00094 struct sockaddr_in answer = { 0, };
00095
00096
00097
00098 ast_mutex_lock(&args.lock);
00099 if (args.stunsock == -1) {
00100 ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
00101 goto monitor_request_cleanup;
00102 }
00103
00104 stun_purge_socket();
00105
00106 if (!(ast_stun_request(args.stunsock, &args.stunaddr, NULL, &answer)) &&
00107 (memcmp(&args.externaladdr, &answer, sizeof(args.externaladdr)))) {
00108 const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
00109 int newport = ntohs(answer.sin_port);
00110
00111 ast_log(LOG_NOTICE, "STUN MONITOR: Old external address/port %s:%d now seen as %s:%d \n",
00112 ast_inet_ntoa(args.externaladdr.sin_addr), ntohs(args.externaladdr.sin_port),
00113 newaddr, newport);
00114
00115 memcpy(&args.externaladdr, &answer, sizeof(args.externaladdr));
00116
00117 if (args.externaladdr_known) {
00118
00119 generate_event = 1;
00120
00121 } else {
00122
00123
00124 args.externaladdr_known = 1;
00125 }
00126 }
00127
00128 if (generate_event) {
00129 struct ast_event *event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
00130 if (!event) {
00131 ast_log(LOG_ERROR, "STUN monitor: could not create AST_EVENT_NETWORK_CHANGE event.\n");
00132 goto monitor_request_cleanup;
00133 }
00134 if (ast_event_queue(event)) {
00135 ast_event_destroy(event);
00136 event = NULL;
00137 ast_log(LOG_ERROR, "STUN monitor: could not queue AST_EVENT_NETWORK_CHANGE event.\n");
00138 goto monitor_request_cleanup;
00139 }
00140 }
00141
00142 monitor_request_cleanup:
00143
00144
00145 res = args.refresh * 1000;
00146 ast_mutex_unlock(&args.lock);
00147
00148 return res;
00149 }
00150
00151
00152
00153
00154 static void stun_stop_monitor(void)
00155 {
00156 if (sched) {
00157 sched = ast_sched_thread_destroy(sched);
00158 ast_log(LOG_NOTICE, "STUN monitor stopped\n");
00159 }
00160
00161
00162 stun_close_sock();
00163 }
00164
00165
00166
00167
00168 static int stun_start_monitor(void)
00169 {
00170 struct ast_sockaddr dst;
00171
00172 stun_close_sock();
00173
00174
00175 ast_sockaddr_from_sin(&dst, &args.stunaddr);
00176
00177
00178 args.stunsock = socket(AF_INET, SOCK_DGRAM, 0);
00179 if (args.stunsock < 0) {
00180 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
00181 return -1;
00182 }
00183
00184 if (ast_connect(args.stunsock, &dst) != 0) {
00185 ast_log(LOG_WARNING, "SIP STUN Failed to connect to %s\n", ast_sockaddr_stringify(&dst));
00186 stun_close_sock();
00187 return -1;
00188 }
00189
00190
00191 if (sched) {
00192 return 0;
00193 }
00194
00195 if (!(sched = ast_sched_thread_create())) {
00196 ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
00197 stun_close_sock();
00198 return -1;
00199 }
00200
00201 if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
00202 ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
00203 sched = ast_sched_thread_destroy(sched);
00204 stun_close_sock();
00205 return -1;
00206 }
00207
00208 ast_log(LOG_NOTICE, "STUN monitor started\n");
00209 return 0;
00210 }
00211
00212 static int load_config(int startup)
00213 {
00214 struct ast_flags config_flags = { 0, };
00215 struct ast_config *cfg;
00216 struct ast_variable *v;
00217
00218 if (!startup) {
00219 ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
00220 }
00221
00222 if (!(cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags)) ||
00223 cfg == CONFIG_STATUS_FILEINVALID) {
00224 ast_log(LOG_ERROR, "Unable to load config %s\n", stun_conf_file);
00225 return -1;
00226 }
00227
00228 if (cfg == CONFIG_STATUS_FILEUNCHANGED && !startup) {
00229 return 0;
00230 }
00231
00232
00233 args.monitor_enabled = 0;
00234 memset(&args.stunaddr, 0, sizeof(args.stunaddr));
00235 args.refresh = DEFAULT_MONITOR_REFRESH;
00236
00237 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00238 if (!strcasecmp(v->name, "stunaddr")) {
00239 args.stunaddr.sin_port = htons(STANDARD_STUN_PORT);
00240 if (ast_parse_arg(v->value, PARSE_INADDR, &args.stunaddr)) {
00241 ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
00242 } else {
00243 ast_log(LOG_NOTICE, "STUN monitor enabled: %s\n", v->value);
00244 args.monitor_enabled = 1;
00245 }
00246 } else if (!strcasecmp(v->name, "stunrefresh")) {
00247 if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
00248 ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
00249 args.refresh = DEFAULT_MONITOR_REFRESH;
00250 } else {
00251 ast_log(LOG_NOTICE, "STUN Monitor set to refresh every %d seconds\n", args.refresh);
00252 }
00253 } else {
00254 ast_log(LOG_WARNING, "SIP STUN: invalid config option %s at line %d\n", v->value, v->lineno);
00255 }
00256 }
00257
00258 ast_config_destroy(cfg);
00259
00260 return 0;
00261 }
00262
00263 static int __reload(int startup)
00264 {
00265 int res;
00266
00267 ast_mutex_lock(&args.lock);
00268 if (!(res = load_config(startup)) && args.monitor_enabled) {
00269 res = stun_start_monitor();
00270 }
00271 ast_mutex_unlock(&args.lock);
00272
00273 if ((res == -1) || !args.monitor_enabled) {
00274 args.monitor_enabled = 0;
00275 stun_stop_monitor();
00276 }
00277
00278 return res;
00279 }
00280
00281 static int reload(void)
00282 {
00283 return __reload(0);
00284 }
00285
00286 static int unload_module(void)
00287 {
00288 stun_stop_monitor();
00289 ast_mutex_destroy(&args.lock);
00290 return 0;
00291 }
00292
00293 static int load_module(void)
00294 {
00295 ast_mutex_init(&args.lock);
00296 args.stunsock = -1;
00297 memset(&args.externaladdr, 0, sizeof(args.externaladdr));
00298 args.externaladdr_known = 0;
00299 sched = NULL;
00300 if (__reload(1)) {
00301 stun_stop_monitor();
00302 ast_mutex_destroy(&args.lock);
00303 return AST_MODULE_LOAD_DECLINE;
00304 }
00305
00306 return AST_MODULE_LOAD_SUCCESS;
00307 }
00308
00309 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
00310 .load = load_module,
00311 .unload = unload_module,
00312 .reload = reload,
00313 .load_pri = AST_MODPRI_CHANNEL_DEPEND
00314 );