/* * Copyright (C) 2019 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * * This program 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. See . * * 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 General Public License * for more details. */ #include "farp_listener.h" #include #include typedef struct private_farp_listener_t private_farp_listener_t; /** * Private data of an farp_listener_t object. */ struct private_farp_listener_t { /** * Public farp_listener_t interface. */ farp_listener_t public; /** * List with entry_t */ linked_list_t *entries; /** * RWlock for IP list */ rwlock_t *lock; }; /** * Traffic selector cache entry */ typedef struct { /** list of local selectors */ linked_list_t *local; /** list of remote selectors */ linked_list_t *remote; /** reqid of CHILD_SA */ uint32_t reqid; } entry_t; /** * Destroy a cache entry */ static void destroy_entry(entry_t *this) { this->local->destroy_offset(this->local, offsetof(traffic_selector_t, destroy)); this->remote->destroy_offset(this->remote, offsetof(traffic_selector_t, destroy)); free(this); } METHOD(listener_t, child_updown, bool, private_farp_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) { enumerator_t *enumerator; traffic_selector_t *ts; entry_t *entry; const chunk_t full_from = chunk_from_chars(0x00, 0x00, 0x00, 0x00), full_to = chunk_from_chars(0xff, 0xff, 0xff, 0xff); if (up) { INIT(entry, .local = linked_list_create(), .remote = linked_list_create(), .reqid = child_sa->get_reqid(child_sa), ); enumerator = child_sa->create_ts_enumerator(child_sa, FALSE); while (enumerator->enumerate(enumerator, &ts)) { if (ts->get_type(ts) != TS_IPV4_ADDR_RANGE) { continue; } /* ignore 0.0.0.0/0 remote TS because we don't want to * reply to ARP requests for locally connected subnets */ if (chunk_equals(ts->get_from_address(ts), full_from) && chunk_equals(ts->get_to_address(ts), full_to)) { continue; } entry->remote->insert_last(entry->remote, ts->clone(ts)); } enumerator->destroy(enumerator); enumerator = child_sa->create_ts_enumerator(child_sa, TRUE); while (enumerator->enumerate(enumerator, &ts)) { if (ts->get_type(ts) != TS_IPV4_ADDR_RANGE) { continue; } entry->local->insert_last(entry->local, ts->clone(ts)); } enumerator->destroy(enumerator); if (!entry->remote->get_count(entry->remote) || !entry->local->get_count(entry->local)) { destroy_entry(entry); return TRUE; } this->lock->write_lock(this->lock); this->entries->insert_last(this->entries, entry); this->lock->unlock(this->lock); } else { this->lock->write_lock(this->lock); enumerator = this->entries->create_enumerator(this->entries); while (enumerator->enumerate(enumerator, &entry)) { if (entry->reqid == child_sa->get_reqid(child_sa)) { this->entries->remove_at(this->entries, enumerator); destroy_entry(entry); break; } } enumerator->destroy(enumerator); this->lock->unlock(this->lock); } return TRUE; } METHOD(farp_listener_t, has_tunnel, bool, private_farp_listener_t *this, host_t *local, host_t *remote) { enumerator_t *entries, *locals, *remotes; traffic_selector_t *ts; bool found = FALSE; entry_t *entry; this->lock->read_lock(this->lock); entries = this->entries->create_enumerator(this->entries); while (!found && entries->enumerate(entries, &entry)) { remotes = entry->remote->create_enumerator(entry->remote); while (!found && remotes->enumerate(remotes, &ts)) { if (ts->includes(ts, remote)) { locals = entry->local->create_enumerator(entry->local); while (!found && locals->enumerate(locals, &ts)) { found = ts->includes(ts, local); } locals->destroy(locals); } } remotes->destroy(remotes); } entries->destroy(entries); this->lock->unlock(this->lock); return found; } METHOD(farp_listener_t, destroy, void, private_farp_listener_t *this) { this->entries->destroy(this->entries); this->lock->destroy(this->lock); free(this); } /** * See header */ farp_listener_t *farp_listener_create() { private_farp_listener_t *this; INIT(this, .public = { .listener = { .child_updown = _child_updown, }, .has_tunnel = _has_tunnel, .destroy = _destroy, }, .entries = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); return &this->public; }