/** * ip address family related structures * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * Kamailio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! * \file * \brief Kamailio core :: ip address family related structures * \ingroup core * Module: \ref core */ #ifndef ip_addr_h #define ip_addr_h #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include "str.h" #include "compiler_opt.h" #include "ut.h" #include "dprint.h" extern str ksr_ipv6_hex_style; typedef enum sip_protos { PROTO_NONE, PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP, PROTO_WS, PROTO_WSS, PROTO_OTHER } sip_protos_t; #define PROTO_LAST PROTO_OTHER #ifdef USE_COMP typedef enum comp_methods { COMP_NONE, COMP_SIGCOMP, COMP_SERGZ } comp_methods_t; #endif typedef struct ip_addr { unsigned int af; /* address family: AF_INET6 or AF_INET */ unsigned int len; /* address len, 16 or 4 */ /* 64 bits aligned address */ union { unsigned long addrl[16/sizeof(long)]; /* long format*/ unsigned int addr32[4]; unsigned short addr16[8]; unsigned char addr[16]; }u; } ip_addr_t; typedef struct net { struct ip_addr ip; struct ip_addr mask; } sr_net_t; typedef union sockaddr_union{ struct sockaddr s; struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr_storage sas; } sr_sockaddr_union_t; typedef enum si_flags { SI_NONE = 0, SI_IS_IP = (1<<0), SI_IS_LO = (1<<1), SI_IS_MCAST = (1<<2), SI_IS_ANY = (1<<3), SI_IS_MHOMED = (1<<4), } si_flags_t; typedef struct addr_info { str name; /* name - eg.: foo.bar or 10.0.0.1 */ struct ip_addr address; /*ip address */ str address_str; /*ip address converted to string -- optimization*/ enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */ union sockaddr_union su; struct addr_info* next; struct addr_info* prev; } addr_info_t; typedef struct advertise_info { str name; /* name - eg.: foo.bar or 10.0.0.1 */ unsigned short port_no; /* port number */ short port_pad; /* padding field */ str port_no_str; /* port number converted to string -- optimization*/ str address_str; /*ip address converted to string -- optimization*/ struct ip_addr address; /* ip address */ str sock_str; /* Socket proto, ip, and port as string */ } advertise_info_t; typedef struct socket_info { int socket; str name; /* name - eg.: foo.bar or 10.0.0.1 */ struct ip_addr address; /* ip address */ str address_str; /*ip address converted to string -- optimization*/ str port_no_str; /* port number converted to string -- optimization*/ enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */ union sockaddr_union su; struct socket_info* next; struct socket_info* prev; unsigned short port_no; /* port number */ char proto; /* tcp or udp*/ char proto_pad0; /* padding field */ short proto_pad1; /* padding field */ str sock_str; /* Socket proto, ip, and port as string */ struct addr_info* addr_info_lst; /* extra addresses (e.g. SCTP mh) */ int workers; /* number of worker processes for this socket */ int workers_tcpidx; /* index of workers in tcp children array */ str sockname; /* socket name given in config listen value */ struct advertise_info useinfo; /* details to be used in SIP msg */ #ifdef USE_MCAST str mcast; /* name of interface that should join multicast group*/ #endif /* USE_MCAST */ } socket_info_t; /* send flags */ typedef enum send_flags { SND_F_FORCE_CON_REUSE = (1 << 0), /* reuse an existing connection or fail */ SND_F_CON_CLOSE = (1 << 1), /* close the connection after sending */ SND_F_FORCE_SOCKET = (1 << 2), /* send socket in dst is forced */ } send_flags_t; typedef struct snd_flags { unsigned short f; /* snd flags */ unsigned short blst_imask; /* blocklist ignore mask */ } snd_flags_t; /* recv flags */ typedef enum recv_flags { RECV_F_INTERNAL = (1 << 0), /* */ } recv_flags_t; typedef struct receive_info { struct ip_addr src_ip; struct ip_addr dst_ip; unsigned short src_port; /* host byte order */ unsigned short dst_port; /* host byte order */ int proto_reserved1; /* tcp stores the connection id here */ int proto_reserved2; union sockaddr_union src_su; /* useful for replies*/ struct socket_info* bind_address; /* sock_info structure on which * the msg was received */ recv_flags_t rflags; /* flags */ char proto; #ifdef USE_COMP char proto_pad0; /* padding field */ short comp; /* compression */ #else char proto_pad0; /* padding field */ short proto_pad1; /* padding field */ #endif /* no need for dst_su yet */ } receive_info_t; typedef struct dest_info { struct socket_info* send_sock; union sockaddr_union to; int id; /* tcp stores the connection id here */ snd_flags_t send_flags; char proto; #ifdef USE_COMP char proto_pad0; /* padding field */ short comp; #else char proto_pad0; /* padding field */ short proto_pad1; /* padding field */ #endif } dest_info_t; typedef struct ksr_coninfo { ip_addr_t src_ip; ip_addr_t dst_ip; unsigned short src_port; /* host byte order */ unsigned short dst_port; /* host byte order */ int proto; socket_info_t *csocket; } ksr_coninfo_t; typedef struct sr_net_info { str data; receive_info_t* rcv; dest_info_t* dst; } sr_net_info_t; sr_net_info_t *ksr_evrt_rcvnetinfo_get(void); #define SND_FLAGS_INIT(sflags) \ do{ \ (sflags)->f=0; \ (sflags)->blst_imask=0; \ }while(0) #define SND_FLAGS_OR(dst, src1, src2) \ do{ \ (dst)->f = (src1)->f | (src2)->f; \ (dst)->blst_imask = (src1)->blst_imask | (src2)->blst_imask; \ }while(0) #define SND_FLAGS_AND(dst, src1, src2) \ do{ \ (dst)->f = (src1)->f & (src2)->f; \ (dst)->blst_imask = (src1)->blst_imask & (src2)->blst_imask; \ }while(0) /* list of names for multi-homed sockets that need to bind on * multiple addresses in the same time (sctp ) */ typedef struct name_lst { char* name; struct name_lst* next; int flags; } name_lst_t; typedef struct socket_id { struct name_lst* addr_lst; /* address list, the first one must * be present and is the main one * (in case of multihoming sctp) */ int flags; int proto; int port; struct socket_id* next; } socket_id_t; /* len of the sockaddr */ #ifdef HAVE_SOCKADDR_SA_LEN #define sockaddru_len(su) ((su).s.sa_len) #else #define sockaddru_len(su) \ (((su).s.sa_family==AF_INET6)?sizeof(struct sockaddr_in6):\ sizeof(struct sockaddr_in)) #endif /* HAVE_SOCKADDR_SA_LEN*/ /* inits an ip_addr with the addr. info from a hostent structure * ip = struct ip_addr* * he= struct hostent* */ #define hostent2ip_addr(ip, he, addr_no) \ do{ \ (ip)->af=(he)->h_addrtype; \ (ip)->len=(he)->h_length; \ memcpy((ip)->u.addr, (he)->h_addr_list[(addr_no)], (ip)->len); \ }while(0) /* gets the protocol family corresponding to a specific address family * ( PF_INET - AF_INET, PF_INET6 - AF_INET6, af for others) */ #define AF2PF(af) (((af)==AF_INET)?PF_INET:((af)==AF_INET6)?PF_INET6:(af)) struct net* mk_new_net(struct ip_addr* ip, struct ip_addr* mask); struct net* mk_new_net_bitlen(struct ip_addr* ip, unsigned int bitlen); int mk_net(struct net* n, struct ip_addr* ip, struct ip_addr* mask); int mk_net_bitlen(struct net* n, struct ip_addr* ip, unsigned int bitlen); int mk_net_str(struct net* dst, str* s); void print_ip(char* prefix, struct ip_addr* ip, char* suffix); void stdout_print_ip(struct ip_addr* ip); void print_net(struct net* net); char* get_proto_name(unsigned int proto); #define proto2a get_proto_name int get_valid_proto_string(unsigned int iproto, int utype, int vtype, str *sproto); #ifdef USE_MCAST /* Returns 1 if the given address is a multicast address */ int is_mcast(struct ip_addr* ip); #endif /* USE_MCAST */ /* returns 1 if the given ip address is INADDR_ANY or IN6ADDR_ANY, * 0 otherwise */ inline static int ip_addr_any(struct ip_addr* ip) { int r; int l; l=ip->len/4; for (r=0; r<l; r++) if (ip->u.addr32[r]!=0) return 0; return 1; } /* returns 1 if the given ip address is a loopback address * 0 otherwise */ inline static int ip_addr_loopback(struct ip_addr* ip) { if (ip->af==AF_INET) return ip->u.addr32[0]==htonl(INADDR_LOOPBACK); else if (ip->af==AF_INET6) return IN6_IS_ADDR_LOOPBACK((struct in6_addr*)ip->u.addr32); return 0; } /* creates an ANY ip_addr (filled with 0, af and len properly set) */ inline static void ip_addr_mk_any(int af, struct ip_addr* ip) { ip->af=af; if (likely(af==AF_INET)){ ip->len=4; ip->u.addr32[0]=0; } else{ ip->len=16; #if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64 /* long is 64 bits */ ip->u.addrl[0]=0; ip->u.addrl[1]=0; #else ip->u.addr32[0]=0; ip->u.addr32[1]=0; ip->u.addr32[2]=0; ip->u.addr32[3]=0; #endif /* ULONG_MAX */ } } /* returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error * [ diff. address families ]) */ inline static int matchnet(struct ip_addr* ip, struct net* net) { unsigned int r; if (ip->af == net->ip.af){ for(r=0; r<ip->len/4; r++){ /* ipv4 & ipv6 addresses are * all multiple of 4*/ if ((ip->u.addr32[r]&net->mask.u.addr32[r]) !=net->ip.u.addr32[r]) { return 0; } } return 1; }; return -1; } /* inits an ip_addr pointer from a sockaddr structure*/ static inline void sockaddr2ip_addr(struct ip_addr* ip, struct sockaddr* sa) { switch(sa->sa_family){ case AF_INET: ip->af=AF_INET; ip->len=4; memcpy(ip->u.addr, &((struct sockaddr_in*)sa)->sin_addr, 4); break; case AF_INET6: ip->af=AF_INET6; ip->len=16; memcpy(ip->u.addr, &((struct sockaddr_in6*)sa)->sin6_addr, 16); break; default: LM_CRIT("unknown address family %d\n", sa->sa_family); } } /* compare 2 ip_addrs (both args are pointers)*/ #define ip_addr_cmp(ip1, ip2) \ (((ip1)->af==(ip2)->af)&& \ (memcmp((ip1)->u.addr, (ip2)->u.addr, (ip1)->len)==0)) /* compare 2 sockaddr_unions */ static inline int su_cmp(const union sockaddr_union* s1, const union sockaddr_union* s2) { if (s1->s.sa_family!=s2->s.sa_family) return 0; switch(s1->s.sa_family){ case AF_INET: return (s1->sin.sin_port==s2->sin.sin_port)&& (memcmp(&s1->sin.sin_addr, &s2->sin.sin_addr, 4)==0); case AF_INET6: return (s1->sin6.sin6_port==s2->sin6.sin6_port)&& (memcmp(&s1->sin6.sin6_addr, &s2->sin6.sin6_addr, 16)==0); default: LM_CRIT("unknown address family %d\n", s1->s.sa_family); return 0; } } /* gets the port number (host byte order) */ static inline unsigned short su_getport(const union sockaddr_union* su) { switch(su->s.sa_family){ case AF_INET: return ntohs(su->sin.sin_port); case AF_INET6: return ntohs(su->sin6.sin6_port); default: LM_CRIT("unknown address family %d\n", su->s.sa_family); return 0; } } /* sets the port number (host byte order) */ static inline void su_setport(union sockaddr_union* su, unsigned short port) { switch(su->s.sa_family){ case AF_INET: su->sin.sin_port=htons(port); break; case AF_INET6: su->sin6.sin6_port=htons(port); break; default: LM_CRIT("unknown address family %d\n", su->s.sa_family); } } /* inits an ip_addr pointer from a sockaddr_union ip address */ static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su) { switch(su->s.sa_family){ case AF_INET: ip->af=AF_INET; ip->len=4; memcpy(ip->u.addr, &su->sin.sin_addr, 4); break; case AF_INET6: ip->af=AF_INET6; ip->len=16; memcpy(ip->u.addr, &su->sin6.sin6_addr, 16); break; default: LM_CRIT("unknown address family %d\n", su->s.sa_family); memset(ip, 0, sizeof(ip_addr_t)); } } /* ip_addr2su -> the same as init_su*/ #define ip_addr2su init_su /* inits a struct sockaddr_union from a struct ip_addr and a port no * returns 0 if ok, -1 on error (unknown address family) * the port number is in host byte order */ static inline int init_su( union sockaddr_union* su, struct ip_addr* ip, unsigned short port ) { memset(su, 0, sizeof(union sockaddr_union));/*needed on freebsd*/ su->s.sa_family=ip->af; switch(ip->af){ case AF_INET6: memcpy(&su->sin6.sin6_addr, ip->u.addr, ip->len); #ifdef HAVE_SOCKADDR_SA_LEN su->sin6.sin6_len=sizeof(struct sockaddr_in6); #endif su->sin6.sin6_port=htons(port); break; case AF_INET: memcpy(&su->sin.sin_addr, ip->u.addr, ip->len); #ifdef HAVE_SOCKADDR_SA_LEN su->sin.sin_len=sizeof(struct sockaddr_in); #endif su->sin.sin_port=htons(port); break; default: LM_CRIT("unknown address family %d\n", ip->af); return -1; } return 0; } /* inits a struct sockaddr_union from a struct hostent, an address index in * the hostent structure and a port no. (host byte order) * WARNING: no index overflow checks! * returns 0 if ok, -1 on error (unknown address family) */ int hostent2su(union sockaddr_union* su, struct hostent* he, unsigned int idx, unsigned short port); /* maximum size of a str returned by ip_addr2str */ #define IP6_MAX_STR_SIZE 39 /*1234:5678:9012:3456:7890:1234:5678:9012*/ #define IP4_MAX_STR_SIZE 15 /*123.456.789.012*/ /* converts a raw ipv6 addr (16 bytes) to ascii */ int ip6tosbuf(unsigned char* ip6, char* buff, int len); /* converts a raw ipv4 addr (4 bytes) to ascii */ int ip4tosbuf(unsigned char* ip4, char* buff, int len); /* fast ip_addr -> string converter; * returns number of bytes written in buf on success, <=0 on error * The buffer must have enough space to hold the maximum size ip address * of the corresponding address (see IP[46] above) or else the function * will return error (no detailed might fit checks are made, for example * if len==7 the function will fail even for 1.2.3.4). */ int ip_addr2sbuf(struct ip_addr* ip, char* buff, int len); /* same as ip_addr2sbuf, but with [ ] around IPv6 addresses */ int ip_addr2sbufz(struct ip_addr* ip, char* buff, int len); /* maximum size of a str returned by ip_addr2a (including \0) */ #define IP_ADDR_MAX_STR_SIZE (IP6_MAX_STR_SIZE+1) /* ip62ascii + \0*/ #define IP_ADDR_MAX_STRZ_SIZE (IP6_MAX_STR_SIZE+3) /* ip62ascii + [ + ] + \0*/ /* fast ip_addr -> string converter; * it uses an internal buffer */ char* ip_addr2a(struct ip_addr* ip); /* full address in text representation, including [] for ipv6 */ char* ip_addr2strz(struct ip_addr* ip); #define SU2A_MAX_STR_SIZE (IP6_MAX_STR_SIZE + 2 /* [] */+\ 1 /* : */ + USHORT2SBUF_MAX_LEN + 1 /* \0 */) /* returns an asciiz string containing the ip and the port * (<ip_addr>:port or [<ipv6_addr>]:port) */ char* su2a(union sockaddr_union* su, int su_len); #define SUIP2A_MAX_STR_SIZE (IP6_MAX_STR_SIZE + 2 /* [] */ + 1 /* \0 */) /* returns an asciiz string containing the ip * (<ipv4_addr> or [<ipv6_addr>]) */ char* suip2a(union sockaddr_union* su, int su_len); /* converts an ip_addr structure to a hostent, returns pointer to internal * statical structure */ struct hostent* ip_addr2he(str* name, struct ip_addr* ip); /* init a dest_info structure */ #define init_dest_info(dst) \ do{ \ memset((dst), 0, sizeof(struct dest_info)); \ } while(0) /* init a dest_info structure from a recv_info structure */ inline static void init_dst_from_rcv(struct dest_info* dst, struct receive_info* rcv) { dst->send_sock=rcv->bind_address; dst->to=rcv->src_su; dst->id=rcv->proto_reserved1; dst->proto=rcv->proto; dst->send_flags.f=0; dst->send_flags.blst_imask=0; #ifdef USE_COMP dst->comp=rcv->comp; #endif } /** * match ip address with net address and bitmask * - return 0 on match, -1 otherwise */ int ip_addr_match_net(ip_addr_t *iaddr, ip_addr_t *naddr, int mask); int si_get_signaling_data(struct socket_info *si, str **addr, str **port); #endif