2 This software is available to you under a choice of one of two
3 licenses. You may choose to be licensed under the terms of the GNU
4 General Public License (GPL) Version 2, available at
5 <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6 license, available in the LICENSE.TXT file accompanying this
7 software. These details are also available at
8 <http://openib.org/license.html>.
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 Copyright (c) 2004 Topspin Communications. All rights reserved.
20 Copyright (c) 2005-2006 Mellanox Technologies Ltd. All rights reserved.
30 #endif /* HAVE_CONFIG_H */
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
43 * SDP specific includes
47 /* --------------------------------------------------------------------- */
48 /* library static and global variables */
49 /* --------------------------------------------------------------------- */
50 extern char *program_invocation_name, *program_invocation_short_name;
54 struct use_family_rule *rule,
58 char addr_buf[MAX_ADDR_STR_LEN];
60 char *target = __sdp_get_family_str( rule->target_family );
61 char *prog = rule->prog_name_expr;
63 /* TODO: handle IPv6 in rule */
64 if ( rule->match_by_addr ) {
65 if ( rule->prefixlen != 32 )
66 sprintf( addr_buf, "%s/%d", inet_ntoa( rule->ipv4 ),
69 sprintf( addr_buf, "%s", inet_ntoa( rule->ipv4 ) );
71 strcpy( addr_buf, "*" );
74 if ( rule->match_by_port )
75 if ( rule->eport > rule->sport )
76 sprintf( ports_buf, "%d", rule->sport );
78 sprintf( ports_buf, "%d-%d", rule->sport, rule->eport );
80 sprintf( ports_buf, "*" );
82 snprintf( buf, len, "use %s %s %s:%s", target, prog, addr_buf, ports_buf );
85 /* return 0 if the addresses match */
88 struct use_family_rule *rule,
89 const struct sockaddr_in *sin )
91 return ( rule->ipv4.s_addr !=
93 s_addr & htonl( SDP_NETMASK( rule->prefixlen ) ) ) );
97 match_ip_addr_and_port(
98 struct use_family_rule *rule,
99 const struct sockaddr *addr_in,
100 const socklen_t addrlen )
102 const struct sockaddr_in *sin = ( const struct sockaddr_in * )addr_in;
103 const struct sockaddr_in6 *sin6 = ( const struct sockaddr_in6 * )addr_in;
104 struct sockaddr_in tmp_sin;
107 char addr_buf[MAX_ADDR_STR_LEN];
108 const char *addr_str;
111 if ( __sdp_log_get_level( ) <= 3 ) {
112 if ( sin6->sin6_family == AF_INET6 ) {
114 inet_ntop( AF_INET6, ( void * )&( sin6->sin6_addr ), addr_buf,
116 port = ntohs( sin6->sin6_port );
119 inet_ntop( AF_INET, ( void * )&( sin->sin_addr ), addr_buf,
121 port = ntohs( sin->sin_port );
123 if ( addr_str == NULL )
124 addr_str = "INVALID_ADDR";
126 get_rule_str( rule, rule_str, sizeof( rule_str ) );
128 __sdp_log( 3, "MATCH: matching %s:%d to %s => \n", addr_str, port,
132 /* We currently only support IPv4 and IPv4 embedded in IPv6 */
133 if ( rule->match_by_port ) {
134 if ( sin6->sin6_family == AF_INET6 )
135 port = ntohs( sin6->sin6_port );
137 port = ntohs( sin->sin_port );
139 if ( ( port < rule->sport ) || ( port > rule->eport ) ) {
140 __sdp_log( 3, "NEGATIVE by port range\n" );
145 if ( match && rule->match_by_addr ) {
146 if ( __sdp_sockaddr_to_sdp( addr_in, addrlen, &tmp_sin, NULL ) ||
147 match_ipv4_addr( rule, &tmp_sin ) ) {
148 __sdp_log( 3, "NEGATIVE by address\n" );
154 __sdp_log( 3, "POSITIVE\n" );
159 /* return 1 on match */
162 struct use_family_rule *rule )
164 return !fnmatch( rule->prog_name_expr, program_invocation_short_name, 0 );
168 get_family_by_first_matching_rule(
169 const struct sockaddr *sin,
170 const socklen_t addrlen,
171 struct use_family_rule *rules )
173 struct use_family_rule *rule;
175 for ( rule = rules; rule != NULL; rule = rule->next ) {
176 /* skip if not our program */
177 if ( !match_program_name( rule ) )
180 /* first rule wins */
181 if ( match_ip_addr_and_port( rule, sin, addrlen ) )
182 return ( rule->target_family );
188 /* return the result of the first matching rule found */
191 const struct sockaddr * sin,
192 const socklen_t addrlen )
194 use_family_t target_family;
196 /* if we do not have any rules we use sdp */
197 if ( __sdp_config_empty( ) )
198 target_family = USE_SDP;
201 get_family_by_first_matching_rule( sin, addrlen,
202 __sdp_servers_family_rules_head );
204 __sdp_log( 4, "MATCH LISTEN: => %s\n",
205 __sdp_get_family_str( target_family ) );
207 return ( target_family );
212 const struct sockaddr * sin,
213 const socklen_t addrlen )
215 use_family_t target_family;
217 /* if we do not have any rules we use sdp */
218 if ( __sdp_config_empty( ) )
219 target_family = USE_SDP;
222 get_family_by_first_matching_rule( sin, addrlen,
223 __sdp_clients_family_rules_head );
225 __sdp_log( 4, "MATCH CONNECT: => %s\n",
226 __sdp_get_family_str( target_family ) );
228 return ( target_family );
231 /* given a set of rules see if there is a global match for current program */
233 match_by_all_rules_program(
234 struct use_family_rule *rules )
238 use_family_t target_family = USE_BOTH;
239 struct use_family_rule *rule;
241 for ( rule = rules; ( rule != NULL ) && ( target_family == USE_BOTH );
242 rule = rule->next ) {
243 /* skip if not our program */
244 if ( !match_program_name( rule ) )
248 * to declare a dont care we either have a dont care address and port
249 * or the previous non global rules use the same target family as the
252 if ( rule->match_by_addr || rule->match_by_port ) {
253 /* not a glocal match rule - just track the target family */
254 if ( rule->target_family == USE_SDP )
256 else if ( rule->target_family == USE_TCP )
259 /* a global match so we can declare a match by program */
260 if ( ( rule->target_family == USE_SDP ) && ( any_tcp == 0 ) )
261 target_family = USE_SDP;
262 else if ( ( rule->target_family == USE_TCP ) && ( any_sdp == 0 ) )
263 target_family = USE_TCP;
266 return ( target_family );
269 /* return tcp or sdp if the port and role are dont cares */
271 __sdp_match_by_program(
274 use_family_t server_target_family;
275 use_family_t client_target_family;
276 use_family_t target_family = USE_BOTH;
278 if ( __sdp_config_empty( ) ) {
279 target_family = USE_SDP;
281 /* need to try both server and client rules */
282 server_target_family =
283 match_by_all_rules_program( __sdp_servers_family_rules_head );
284 client_target_family =
285 match_by_all_rules_program( __sdp_clients_family_rules_head );
287 /* only if both agree */
288 if ( server_target_family == client_target_family )
289 target_family = server_target_family;
292 __sdp_log( 4, "MATCH PROGRAM: => %s\n",
293 __sdp_get_family_str( target_family ) );
295 return ( target_family );