/* BAREOSĀ® - Backup Archiving REcovery Open Sourced Copyright (C) 2004-2011 Free Software Foundation Europe e.V. Copyright (C) 2011-2012 Planets Communications B.V. Copyright (C) 2013-2020 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero 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. */ /* * Written by Meno Abels, June MMIV */ /** * @file * Configuration file parser for IP-Addresse ipv4 and ipv6 */ #include "include/bareos.h" #include "lib/address_conf.h" #include "lib/bnet.h" #include "lib/bsys.h" #include "lib/edit.h" #include "lib/output_formatter_resource.h" #ifdef HAVE_ARPA_NAMESER_H # include #endif #ifdef HAVE_RESOLV_H //#include #endif IPADDR::IPADDR() : type(R_UNDEFINED) , saddr(nullptr) , saddr4(nullptr) #ifdef HAVE_IPV6 , saddr6(nullptr) #endif { memset(&saddrbuf, 0, sizeof(saddrbuf)); } IPADDR::IPADDR(const IPADDR& src) : IPADDR() { type = src.type; memcpy(&saddrbuf, &src.saddrbuf, sizeof(saddrbuf)); saddr = &saddrbuf.dontuse; saddr4 = &saddrbuf.dontuse4; #ifdef HAVE_IPV6 saddr6 = &saddrbuf.dontuse6; #endif } IPADDR::IPADDR(int af) : IPADDR() { type = R_EMPTY; #ifdef HAVE_IPV6 if (!(af == AF_INET6 || af == AF_INET)) { Emsg1(M_ERROR_TERM, 0, _("Only ipv4 and ipv6 are supported (%d)\n"), af); } #else if (af != AF_INET) { Emsg1(M_ERROR_TERM, 0, _("Only ipv4 is supported (%d)\n"), af); } #endif memset(&saddrbuf, 0, sizeof(saddrbuf)); saddr = &saddrbuf.dontuse; saddr4 = &saddrbuf.dontuse4; #ifdef HAVE_IPV6 saddr6 = &saddrbuf.dontuse6; #endif saddr->sa_family = af; switch (af) { case AF_INET: saddr4->sin_port = 0xffff; break; #ifdef HAVE_IPV6 case AF_INET6: saddr6->sin6_port = 0xffff; break; #endif } SetAddrAny(); } void IPADDR::SetType(i_type o) { type = o; } IPADDR::i_type IPADDR::GetType() const { return type; } unsigned short IPADDR::GetPortNetOrder() const { unsigned short port = 0; if (saddr->sa_family == AF_INET) { port = saddr4->sin_port; } #ifdef HAVE_IPV6 else { port = saddr6->sin6_port; } #endif return port; } void IPADDR::SetPortNet(unsigned short port) { if (saddr->sa_family == AF_INET) { saddr4->sin_port = port; } #ifdef HAVE_IPV6 else { saddr6->sin6_port = port; } #endif } int IPADDR::GetFamily() const { return saddr->sa_family; } struct sockaddr* IPADDR::get_sockaddr() { return saddr; } int IPADDR::GetSockaddrLen() { #ifdef HAVE_IPV6 return saddr->sa_family == AF_INET ? sizeof(*saddr4) : sizeof(*saddr6); #else return sizeof(*saddr4); #endif } void IPADDR::CopyAddr(IPADDR* src) { if (saddr->sa_family == AF_INET) { saddr4->sin_addr.s_addr = src->saddr4->sin_addr.s_addr; } #ifdef HAVE_IPV6 else { saddr6->sin6_addr = src->saddr6->sin6_addr; } #endif } void IPADDR::SetAddrAny() { if (saddr->sa_family == AF_INET) { saddr4->sin_addr.s_addr = INADDR_ANY; } #ifdef HAVE_IPV6 else { saddr6->sin6_addr = in6addr_any; } #endif } void IPADDR::SetAddr4(struct in_addr* ip4) { if (saddr->sa_family != AF_INET) { Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv6 address to a ipv4(%d)\n"), saddr->sa_family); } saddr4->sin_addr = *ip4; } #ifdef HAVE_IPV6 void IPADDR::SetAddr6(struct in6_addr* ip6) { if (saddr->sa_family != AF_INET6) { Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv4 address to a ipv6(%d)\n"), saddr->sa_family); } saddr6->sin6_addr = *ip6; } #endif const char* IPADDR::GetAddress(char* outputbuf, int outlen) { outputbuf[0] = '\0'; #ifdef HAVE_INET_NTOP # ifdef HAVE_IPV6 inet_ntop(saddr->sa_family, saddr->sa_family == AF_INET ? (void*)&(saddr4->sin_addr) : (void*)&(saddr6->sin6_addr), outputbuf, outlen); # else inet_ntop(saddr->sa_family, (void*)&(saddr4->sin_addr), outputbuf, outlen); # endif #else bstrncpy(outputbuf, inet_ntoa(saddr4->sin_addr), outlen); #endif return outputbuf; } void IPADDR::BuildConfigString(OutputFormatterResource& send, bool as_comment) { char tmp[1024]; std::string formatstring; switch (GetFamily()) { case AF_INET: send.SubResourceStart("ipv4", as_comment, "%s = {\n"); send.KeyString("addr", GetAddress(tmp, sizeof(tmp) - 1), as_comment); send.KeyUnsignedInt("port", GetPortHostOrder(), as_comment); send.SubResourceEnd("ipv4", as_comment); break; case AF_INET6: send.SubResourceStart("ipv6", as_comment, "%s = {\n"); send.KeyString("addr", GetAddress(tmp, sizeof(tmp) - 1), as_comment); send.KeyUnsignedInt("port", GetPortHostOrder(), as_comment); send.SubResourceEnd("ipv6", as_comment); break; default: break; } } const char* IPADDR::build_address_str(char* buf, int blen, bool print_port /*=true*/) { char tmp[1024]; if (print_port) { switch (GetFamily()) { case AF_INET: Bsnprintf(buf, blen, "host[ipv4;%s;%hu] ", GetAddress(tmp, sizeof(tmp) - 1), GetPortHostOrder()); break; case AF_INET6: Bsnprintf(buf, blen, "host[ipv6;%s;%hu] ", GetAddress(tmp, sizeof(tmp) - 1), GetPortHostOrder()); break; default: break; } } else { switch (GetFamily()) { case AF_INET: Bsnprintf(buf, blen, "host[ipv4;%s] ", GetAddress(tmp, sizeof(tmp) - 1)); break; case AF_INET6: Bsnprintf(buf, blen, "host[ipv6;%s] ", GetAddress(tmp, sizeof(tmp) - 1)); break; default: break; } } return buf; } const char* BuildAddressesString(dlist* addrs, char* buf, int blen, bool print_port /*=true*/) { if (!addrs || addrs->size() == 0) { bstrncpy(buf, "", blen); return buf; } char* work = buf; IPADDR* p; foreach_dlist (p, addrs) { char tmp[1024]; int len = Bsnprintf(work, blen, "%s", p->build_address_str(tmp, sizeof(tmp), print_port)); if (len < 0) break; work += len; blen -= len; } return buf; } const char* GetFirstAddress(dlist* addrs, char* outputbuf, int outlen) { return ((IPADDR*)(addrs->first()))->GetAddress(outputbuf, outlen); } int GetFirstPortNetOrder(dlist* addrs) { if (!addrs) { return 0; } else { return ((IPADDR*)(addrs->first()))->GetPortNetOrder(); } } int GetFirstPortHostOrder(dlist* addrs) { if (!addrs) { return 0; } else { return ((IPADDR*)(addrs->first()))->GetPortHostOrder(); } } int AddAddress(dlist** out, IPADDR::i_type type, unsigned short defaultport, int family, const char* hostname_str, const char* port_str, char* buf, int buflen) { IPADDR* iaddr; IPADDR* jaddr; dlist* hostaddrs; unsigned short port; IPADDR::i_type intype = type; buf[0] = 0; dlist* addrs = (dlist*)(*(out)); if (!addrs) { IPADDR* tmp = 0; addrs = *out = new dlist(tmp, &tmp->link); } type = (type == IPADDR::R_SINGLE_PORT || type == IPADDR::R_SINGLE_ADDR) ? IPADDR::R_SINGLE : type; if (type != IPADDR::R_DEFAULT) { IPADDR* def = 0; foreach_dlist (iaddr, addrs) { if (iaddr->GetType() == IPADDR::R_DEFAULT) { def = iaddr; } else if (iaddr->GetType() != type) { Bsnprintf(buf, buflen, _("the old style addresses cannot be mixed with new style")); return 0; } } if (def) { addrs->remove(def); delete def; } } if (!port_str || port_str[0] == '\0') { port = defaultport; } else { int pnum = atol(port_str); if (0 < pnum && pnum < 0xffff) { port = htons(pnum); } else { struct servent* s = getservbyname(port_str, "tcp"); if (s) { port = s->s_port; } else { Bsnprintf(buf, buflen, _("can't resolve service(%s)"), port_str); return 0; } } } const char* myerrstr; hostaddrs = BnetHost2IpAddrs(hostname_str, family, &myerrstr); if (!hostaddrs) { Bsnprintf(buf, buflen, _("can't resolve hostname(%s) %s"), hostname_str, myerrstr); return 0; } if (intype == IPADDR::R_SINGLE_PORT || intype == IPADDR::R_SINGLE_ADDR) { IPADDR* addr; if (addrs->size()) { addr = (IPADDR*)addrs->first(); } else { addr = new IPADDR(family); addr->SetType(type); addr->SetPortNet(defaultport); addr->SetAddrAny(); addrs->append(addr); } if (intype == IPADDR::R_SINGLE_PORT) { addr->SetPortNet(port); } if (intype == IPADDR::R_SINGLE_ADDR) { addr->CopyAddr((IPADDR*)(hostaddrs->first())); } } else { foreach_dlist (iaddr, hostaddrs) { IPADDR* clone; /* for duplicates */ foreach_dlist (jaddr, addrs) { if (iaddr->GetSockaddrLen() == jaddr->GetSockaddrLen() && !memcmp(iaddr->get_sockaddr(), jaddr->get_sockaddr(), iaddr->GetSockaddrLen())) { goto skip; /* no price */ } } clone = new IPADDR(*iaddr); clone->SetType(type); clone->SetPortNet(port); addrs->append(clone); skip: continue; } } FreeAddresses(hostaddrs); return 1; } void InitDefaultAddresses(dlist** out, const char* port) { char buf[1024]; unsigned short sport = str_to_int32(port); if (!AddAddress(out, IPADDR::R_DEFAULT, htons(sport), AF_INET, 0, 0, buf, sizeof(buf))) { Emsg1(M_ERROR_TERM, 0, _("Can't add default address (%s)\n"), buf); } } void FreeAddresses(dlist* addrs) { while (!addrs->empty()) { IPADDR* ptr = (IPADDR*)addrs->first(); addrs->remove(ptr); delete ptr; } delete addrs; } int SockaddrGetPortNetOrder(const struct sockaddr* client_addr) { if (client_addr->sa_family == AF_INET) { return ((struct sockaddr_in*)client_addr)->sin_port; } #ifdef HAVE_IPV6 else { return ((struct sockaddr_in6*)client_addr)->sin6_port; } #endif return -1; } int SockaddrGetPort(const struct sockaddr* client_addr) { if (client_addr->sa_family == AF_INET) { return ntohs(((struct sockaddr_in*)client_addr)->sin_port); } #ifdef HAVE_IPV6 else { return ntohs(((struct sockaddr_in6*)client_addr)->sin6_port); } #endif return -1; } char* SockaddrToAscii(const struct sockaddr* sa, char* buf, int len) { #ifdef HAVE_INET_NTOP /* MA Bug 5 the problem was that i mixed up sockaddr and in_addr */ inet_ntop(sa->sa_family, # ifdef HAVE_IPV6 sa->sa_family == AF_INET ? (void*)&(((struct sockaddr_in*)sa)->sin_addr) : (void*)&(((struct sockaddr_in6*)sa)->sin6_addr), # else (void*)&(((struct sockaddr_in*)sa)->sin_addr), # endif /* HAVE_IPV6 */ buf, len); #else bstrncpy(buf, inet_ntoa(((struct sockaddr_in*)sa)->sin_addr), len); #endif return buf; } #ifdef HAVE_OLD_SOCKOPT int inet_aton(const char* cp, struct in_addr* inp) { struct in_addr inaddr; if ((inaddr.s_addr = InetAddr(cp)) != INADDR_NONE) { inp->s_addr = inaddr.s_addr; return 1; } return 0; } #endif