@@ -597,8 +597,6 @@ static int reload_verify(int reload)
597
597
}
598
598
}
599
599
600
- ast_debug (1 , "New profile: '%s'\n" , cat );
601
-
602
600
if (!v ) {
603
601
/* Make one then */
604
602
v = alloc_profile (cat );
@@ -629,7 +627,6 @@ static int reload_verify(int reload)
629
627
/* Search Config */
630
628
var = ast_variable_browse (cfg , cat );
631
629
while (var ) {
632
- ast_debug (2 , "Logging parameter %s with value %s from lineno %d\n" , var -> name , var -> value , var -> lineno );
633
630
profile_set_param (v , var -> name , var -> value , var -> lineno , 1 );
634
631
var = var -> next ;
635
632
} /* End while(var) loop */
@@ -648,7 +645,7 @@ static int reload_verify(int reload)
648
645
return 0 ;
649
646
}
650
647
651
- /* Copied from func_curl.c. Should be public API? */
648
+ /* Copied from func_curl.c */
652
649
static int url_is_vulnerable (const char * url )
653
650
{
654
651
if (strpbrk (url , "\r\n" )) {
@@ -1011,14 +1008,38 @@ static int v_success(char *name, int in)
1011
1008
return 0 ;
1012
1009
}
1013
1010
1011
+ static const char * stir_shaken_name (char c )
1012
+ {
1013
+ switch (c ) {
1014
+ case 'A' :
1015
+ return "Full Attestation" ;
1016
+ case 'B' :
1017
+ return "Partial Attestation" ;
1018
+ case 'C' :
1019
+ return "Gateway Attestation" ;
1020
+ case 'D' :
1021
+ return "No Validation" ;
1022
+ case 'E' :
1023
+ return "Empty (No parameter)" ;
1024
+ case 'F' :
1025
+ return "Failed Validation" ;
1026
+ default :
1027
+ break ;
1028
+ }
1029
+ ast_assert (0 );
1030
+ return "" ;
1031
+ }
1032
+
1014
1033
static char ss_handle_verstat (const char * verstat )
1015
1034
{
1016
1035
ast_assert (!ast_strlen_zero (verstat ));
1017
- if (!strcmp (verstat , "TN-Validation-Passed" ) || !strcmp (verstat , "TN-Validation-Passed-A" )) {
1036
+ /* Treat TN-Validation-Passed as 'C' since Passed on its own doesn't convey a particular attestation,
1037
+ * it just means the validation was done successfully. So, if that's all the info we have, assume the worst. */
1038
+ if (!strcmp (verstat , "TN-Validation-Passed-A" )) {
1018
1039
return 'A' ;
1019
1040
} else if (!strcmp (verstat , "TN-Validation-Passed-B" )) {
1020
1041
return 'B' ;
1021
- } else if (!strcmp (verstat , "TN-Validation-Passed-C" )) {
1042
+ } else if (!strcmp (verstat , "TN-Validation-Passed-C" ) || ! strcmp ( verstat , "TN-Validation-Passed" ) ) {
1022
1043
return 'C' ;
1023
1044
} else if (!strcmp (verstat , "No-TN-Validation" )) {
1024
1045
return 'D' ;
@@ -1081,6 +1102,84 @@ static void stir_shaken_stat_inc(int type, char c)
1081
1102
ast_mutex_unlock (& ss_lock );
1082
1103
}
1083
1104
1105
+ static char parse_pai_header (struct ast_channel * chan , const char * headername )
1106
+ {
1107
+ int res ;
1108
+ char headerfunc [48 ];
1109
+ char headerval [512 ] = "" ;
1110
+ char * verstat = NULL ; /* At the moment, not used anymore */
1111
+
1112
+ if (!strcmp (ast_channel_tech (chan )-> type , "PJSIP" )) {
1113
+ snprintf (headerfunc , sizeof (headerfunc ), "PJSIP_HEADER(read,%s,1)" , headername );
1114
+ } else { /* SIP */
1115
+ snprintf (headerfunc , sizeof (headerfunc ), "SIP_HEADER(%s,1)" , headername );
1116
+ }
1117
+ res = ast_func_read (chan , headerfunc , headerval , sizeof (headerval ));
1118
+ if (res || ast_strlen_zero (headerval )) {
1119
+ return 0 ;
1120
+ }
1121
+ return parse_hdr_for_verstat (headername , headerval , & verstat );
1122
+ }
1123
+
1124
+ static void parse_stir_shaken (struct ast_channel * chan , const char * stirshaken_var )
1125
+ {
1126
+ char attestation_hdr [128 ] = "" ;
1127
+ int res ;
1128
+ char ss_verstat ;
1129
+
1130
+ /* STIR/SHAKEN references (including carrier implementations) consulted, in no particular order:
1131
+ * https://www.carrierx.com/documentation/how-it-works/stir-shaken#introduction
1132
+ * https://help.webex.com/en-us/article/8j6te9/Spam-or-fraud-call-indication-in-Webex-Calling
1133
+ * https://www.metaswitch.com/knowledge-center/reference/what-is-stir/shaken
1134
+ * https://www.vitelity.com/frequently-asked-questions-about-stir-shaken/
1135
+ * https://doc.didww.com/services/did/stir-shaken.html
1136
+ * https://support.telnyx.com/en/articles/5402969-stir-shaken-with-telnyx
1137
+ * https://transnexus.com/whitepapers/shaken-vs/
1138
+ * https://www.plivo.com/docs/sip-trunking/concepts/stir-shaken
1139
+ */
1140
+
1141
+ if (strcmp (ast_channel_tech (chan )-> type , "PJSIP" ) && strcmp (ast_channel_tech (chan )-> type , "SIP" )) {
1142
+ ast_log (LOG_WARNING , "STIR/SHAKEN only supported on PJSIP channels\n" );
1143
+ return ;
1144
+ }
1145
+
1146
+ #define VALID_ATTESTATION (c ) (c == 'A' || c == 'B' || c == 'C')
1147
+
1148
+ /* Check P-Attestation-Indicator header.
1149
+ * If it has an attestation value, we can use that directly. */
1150
+ if (!strcmp (ast_channel_tech (chan )-> type , "PJSIP" )) {
1151
+ res = ast_func_read (chan , "PJSIP_HEADER(read,P-Attestation-Indicator,1)" , attestation_hdr , sizeof (attestation_hdr ));
1152
+ } else { /* SIP */
1153
+ res = ast_func_read (chan , "SIP_HEADER(P-Attestation-Indicator,1)" , attestation_hdr , sizeof (attestation_hdr ));
1154
+ }
1155
+ if (!res && !ast_strlen_zero (attestation_hdr )) {
1156
+ ss_verstat = attestation_hdr [0 ];
1157
+ if (VALID_ATTESTATION (ss_verstat )) {
1158
+ goto done ;
1159
+ }
1160
+ ast_log (LOG_WARNING , "Invalid P-Attestation-Indicator header value '%s'\n" , attestation_hdr );
1161
+ }
1162
+
1163
+ /* Check the P-Asserted-Identity header, then the From header if it's not present there */
1164
+ ss_verstat = parse_pai_header (chan , "P-Asserted-Identity" );
1165
+ if (!ss_verstat ) {
1166
+ ss_verstat = parse_pai_header (chan , "From" );
1167
+ }
1168
+
1169
+ done :
1170
+ if (ss_verstat ) {
1171
+ char ss_result [2 ];
1172
+ ast_verb (4 , "STIR/SHAKEN attestation rating is '%c' (%s)\n" , ss_verstat , stir_shaken_name (ss_verstat ));
1173
+ snprintf (ss_result , sizeof (ss_result ), "%c" , ss_verstat );
1174
+ pbx_builtin_setvar_helper (chan , stirshaken_var , ss_result );
1175
+ stir_shaken_stat_inc (0 , ss_verstat );
1176
+ } else {
1177
+ ast_debug (2 , "No STIR/SHAKEN information available\n" );
1178
+ pbx_builtin_setvar_helper (chan , stirshaken_var , "E" );
1179
+ stir_shaken_stat_inc (0 , 'E' );
1180
+ }
1181
+ }
1182
+
1084
1183
#define VERIFY_STRDUP (field ) ast_copy_string(field, v->field, sizeof(field));
1085
1184
1086
1185
static int verify_exec (struct ast_channel * chan , const char * data )
@@ -1187,57 +1286,7 @@ static int verify_exec(struct ast_channel *chan, const char *data)
1187
1286
1188
1287
/* Analyze STIR/SHAKEN result, if applicable */
1189
1288
if (!ast_strlen_zero (stirshaken_var )) {
1190
- char ss_verstat = 0 ;
1191
- char * verstat = NULL ;
1192
- char from_hdr [512 ];
1193
- char pai_hdr [512 ];
1194
- char ss_result [2 ];
1195
- int unsupported = 0 ;
1196
-
1197
- from_hdr [0 ] = pai_hdr [0 ] = '\0' ;
1198
-
1199
- if (!strcmp (ast_channel_tech (chan )-> type , "PJSIP" )) {
1200
- ast_func_read (chan , "PJSIP_HEADER(read,From,1)" , from_hdr , sizeof (from_hdr ));
1201
- ast_func_read (chan , "PJSIP_HEADER(read,P-Asserted-Identity,1)" , pai_hdr , sizeof (pai_hdr ));
1202
- } else if (!strcmp (ast_channel_tech (chan )-> type , "SIP" )) {
1203
- ast_func_read (chan , "SIP_HEADER(From,1)" , from_hdr , sizeof (from_hdr ));
1204
- ast_func_read (chan , "SIP_HEADER(P-Asserted-Identity,1)" , pai_hdr , sizeof (pai_hdr ));
1205
- } else {
1206
- ast_log (LOG_WARNING , "STIR/SHAKEN only supported on PJSIP channels\n" );
1207
- unsupported = 1 ;
1208
- }
1209
- if (!unsupported ) {
1210
- /* STIR/SHAKEN references (including carrier implementations) consulted, in no particular order:
1211
- * https://www.carrierx.com/documentation/how-it-works/stir-shaken#introduction
1212
- * https://help.webex.com/en-us/article/8j6te9/Spam-or-fraud-call-indication-in-Webex-Calling
1213
- * https://www.metaswitch.com/knowledge-center/reference/what-is-stir/shaken
1214
- * https://www.vitelity.com/frequently-asked-questions-about-stir-shaken/
1215
- * https://doc.didww.com/services/did/stir-shaken.html
1216
- * https://support.telnyx.com/en/articles/5402969-stir-shaken-with-telnyx
1217
- * https://transnexus.com/whitepapers/shaken-vs/
1218
- * https://www.plivo.com/docs/sip-trunking/concepts/stir-shaken
1219
- */
1220
-
1221
- if (ast_strlen_zero (from_hdr )) {
1222
- ast_log (LOG_WARNING , "From header is empty?\n" ); /* How can there not be a From header? */
1223
- } else {
1224
- ss_verstat = parse_hdr_for_verstat ("From" , from_hdr , & verstat );
1225
- }
1226
- if (!ss_verstat ) { /* Didn't find anything in the From header, let's try the PAI header now */
1227
- ss_verstat = parse_hdr_for_verstat ("P-Asserted-Identity" , pai_hdr , & verstat );
1228
- }
1229
-
1230
- if (ss_verstat ) {
1231
- ast_verb (4 , "STIR/SHAKEN rating is '%c' (%s)\n" , ss_verstat , S_OR (verstat , "UNKNOWN" ));
1232
- snprintf (ss_result , sizeof (ss_result ), "%c" , ss_verstat );
1233
- pbx_builtin_setvar_helper (chan , stirshaken_var , ss_result );
1234
- stir_shaken_stat_inc (0 , ss_verstat );
1235
- } else {
1236
- ast_debug (2 , "No STIR/SHAKEN information available\n" );
1237
- pbx_builtin_setvar_helper (chan , stirshaken_var , "E" );
1238
- stir_shaken_stat_inc (0 , 'E' );
1239
- }
1240
- }
1289
+ parse_stir_shaken (chan , stirshaken_var );
1241
1290
} else if (!ast_strlen_zero (remote_stirshaken_var )) {
1242
1291
/* If remote result available, use that purely to update the statistics. */
1243
1292
char result [3 ];
@@ -1253,6 +1302,8 @@ static int verify_exec(struct ast_channel *chan, const char *data)
1253
1302
stir_shaken_stat_inc (1 , ss_verstat );
1254
1303
/* Don't automatically set the local var to the remote var, setinvars will do this, if requested. */
1255
1304
}
1305
+ } else {
1306
+ ast_debug (3 , "No STIR/SHAKEN analysis requested\n" );
1256
1307
}
1257
1308
1258
1309
if (method == 2 ) {
@@ -1841,28 +1892,6 @@ static int outverify_exec(struct ast_channel *chan, const char *data)
1841
1892
return 0 ;
1842
1893
}
1843
1894
1844
- static const char * stir_shaken_name (char c )
1845
- {
1846
- switch (c ) {
1847
- case 'A' :
1848
- return "A: Full Attestation" ;
1849
- case 'B' :
1850
- return "B: Partial Attestation" ;
1851
- case 'C' :
1852
- return "C: Gateway Attestation" ;
1853
- case 'D' :
1854
- return "D: No Validation" ;
1855
- case 'E' :
1856
- return "E: Empty (No parameter)" ;
1857
- case 'F' :
1858
- return "F: Failed Validation" ;
1859
- default :
1860
- break ;
1861
- }
1862
- ast_assert (0 );
1863
- return "" ;
1864
- }
1865
-
1866
1895
static char * handle_show_stirshaken (struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
1867
1896
{
1868
1897
unsigned int total [2 ];
@@ -1883,7 +1912,7 @@ static char *handle_show_stirshaken(struct ast_cli_entry *e, int cmd, struct ast
1883
1912
1884
1913
ast_cli (a -> fd , "%-30s %14s %14s\n" , "STIR/SHAKEN Rating" , "# Direct Calls" , "Passthru Calls" );
1885
1914
for (c = 'A' ; c <= 'F' ; c ++ ) {
1886
- ast_cli (a -> fd , "%-30s %14u %14u\n" , stir_shaken_name (c ), stir_shaken_stats [0 ][c - 'A' ], stir_shaken_stats [1 ][c - 'A' ]);
1915
+ ast_cli (a -> fd , "%c: %-27s %14u %14u\n" , c , stir_shaken_name (c ), stir_shaken_stats [0 ][c - 'A' ], stir_shaken_stats [1 ][c - 'A' ]);
1887
1916
total [0 ] += stir_shaken_stats [0 ][c - 'A' ];
1888
1917
total [1 ] += stir_shaken_stats [1 ][c - 'A' ];
1889
1918
}
0 commit comments