osmo-epdg: add a UE object together with an in memory db
This commit is contained in:
parent
2dfe87749f
commit
6f3e8f5ecd
|
@ -23,4 +23,5 @@ libstrongswan_osmo_epdg_la_SOURCES = \
|
|||
gsup_client.h gsup_client.c \
|
||||
ipa_client.h ipa_client.c \
|
||||
osmo_epdg_utils.h osmo_epdg_utils.c \
|
||||
osmo_epdg_ue.h osmo_epdg_ue.c \
|
||||
osmo_epdg_db.h osmo_epdg_db.c
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <daemon.h>
|
||||
#include <plugins/plugin.h>
|
||||
#include <collections/hashtable.h>
|
||||
#include <threading/rwlock.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "osmo_epdg_plugin.h"
|
||||
|
@ -36,94 +37,126 @@ struct private_osmo_epdg_db_t {
|
|||
*/
|
||||
osmo_epdg_db_t public;
|
||||
|
||||
/**
|
||||
* GSUP client
|
||||
*/
|
||||
osmo_epdg_gsup_client_t *gsup;
|
||||
|
||||
/**
|
||||
* subscriber hash by ID
|
||||
*/
|
||||
hashtable_t *subscribers;
|
||||
|
||||
/**
|
||||
* subscriber hash by imsi (how to handle multiple?)
|
||||
*/
|
||||
hashtable_t *subscribers_imsi;
|
||||
|
||||
/**
|
||||
* subscriber by ike_sa
|
||||
* rwlock to lock access for changes
|
||||
*/
|
||||
hashtable_t *subscribers_ike_sa_t;
|
||||
rwlock_t *lock;
|
||||
};
|
||||
|
||||
METHOD(osmo_epdg_db_t, create_subscriber_imsi, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa,
|
||||
char *imsi)
|
||||
METHOD(osmo_epdg_db_t, create_subscriber, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
return NULL;
|
||||
osmo_epdg_ue_t *ue;
|
||||
char imsi[16] = {0};
|
||||
uint32_t unique = ike_sa->get_unique_id(ike_sa);
|
||||
|
||||
if (get_imsi_ike(ike_sa, imsi, sizeof(imsi) - 1))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
ue = this->subscribers_imsi->get(this->subscribers_imsi, imsi);
|
||||
if (ue)
|
||||
{
|
||||
/* TODO: handle dups! */
|
||||
this->lock->unlock(this->lock);
|
||||
return ue;
|
||||
}
|
||||
|
||||
ue = osmo_epdg_ue_create(unique, imsi);
|
||||
if (!ue)
|
||||
{
|
||||
DBG1(DBG_NET, "epdg_db: failed to create UE!");
|
||||
this->lock->unlock(this->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->subscribers_imsi->put(this->subscribers_imsi, ue->get_imsi(ue), ue);
|
||||
|
||||
ue->get(ue);
|
||||
this->lock->unlock(this->lock);
|
||||
return ue;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, get_subscriber_imsi, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, char *imsi, int offset)
|
||||
METHOD(osmo_epdg_db_t, get_subscriber, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, char *imsi)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, get_subscriber_id, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, uint32_t id)
|
||||
{
|
||||
return NULL;
|
||||
osmo_epdg_ue_t *ue;
|
||||
this->lock->read_lock(this->lock);
|
||||
ue = this->subscribers_imsi->get(this->subscribers_imsi, imsi);
|
||||
if (ue)
|
||||
{
|
||||
ue->get(ue);
|
||||
}
|
||||
this->lock->unlock(this->lock);
|
||||
return ue;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, get_subscriber_ike, osmo_epdg_ue_t *,
|
||||
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
|
||||
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
return NULL;
|
||||
char imsi[16] = {0};
|
||||
|
||||
if (get_imsi_ike(ike_sa, imsi, sizeof(imsi)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return this->public.get_subscriber(&this->public, imsi);
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, destroy_subscriber_id, void,
|
||||
private_osmo_epdg_db_t *this, uint32_t id)
|
||||
METHOD(osmo_epdg_db_t, remove_subscriber, void,
|
||||
private_osmo_epdg_db_t *this, const char *imsi)
|
||||
{
|
||||
return;
|
||||
osmo_epdg_ue_t *ue;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
ue = this->subscribers_imsi->remove(this->subscribers_imsi, imsi);
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
if (ue)
|
||||
{
|
||||
ue->put(ue);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, destroy_subscriber_ike, void,
|
||||
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
|
||||
CALLBACK(destroy_ue, void,
|
||||
osmo_epdg_ue_t *ue, const void *key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, destroy_subscriber, void,
|
||||
private_osmo_epdg_db_t *this, osmo_epdg_ue_t *ue)
|
||||
{
|
||||
return;
|
||||
ue->put(ue);
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_db_t, destroy, void,
|
||||
private_osmo_epdg_db_t *this)
|
||||
{
|
||||
this->subscribers_imsi->destroy_function(this->subscribers_imsi, destroy_ue);
|
||||
this->lock->destroy(this->lock);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
osmo_epdg_db_t *osmo_epdg_db_create(osmo_epdg_gsup_client_t *gsup)
|
||||
osmo_epdg_db_t *osmo_epdg_db_create()
|
||||
{
|
||||
private_osmo_epdg_db_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.create_subscriber = _create_subscriber_imsi,
|
||||
.get_subscriber_id = _get_subscriber_id,
|
||||
.get_subscriber_imsi = _get_subscriber_imsi,
|
||||
.create_subscriber = _create_subscriber,
|
||||
.get_subscriber = _get_subscriber,
|
||||
.get_subscriber_ike = _get_subscriber_ike,
|
||||
.destroy_subscriber_ike = _destroy_subscriber_ike,
|
||||
.destroy_subscriber_id = _destroy_subscriber_id,
|
||||
.destroy_subscriber = _destroy_subscriber,
|
||||
.remove_subscriber = _remove_subscriber,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.subscribers_imsi = hashtable_create(hashtable_hash_str, hashtable_equals_str, 128),
|
||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
|
|
|
@ -28,48 +28,37 @@
|
|||
|
||||
#include <bus/listeners/listener.h>
|
||||
#include "gsup_client.h"
|
||||
#include "osmo_epdg_ue.h"
|
||||
#include "osmo_epdg_utils.h"
|
||||
|
||||
typedef struct osmo_epdg_db_t osmo_epdg_db_t;
|
||||
|
||||
/**
|
||||
* SIM listener implementation using a set of AKA functions.
|
||||
* DB object to store state across different threads.
|
||||
*/
|
||||
struct osmo_epdg_db_t {
|
||||
/**
|
||||
* Create new subscriber by imsi, before sending authentication
|
||||
* Create new subscriber by imsi, before sending authentication.
|
||||
* NULL or UE object. The UE object need to called put() when not used.
|
||||
*/
|
||||
osmo_epdg_ue_t *(*create_subscriber)(osmo_epdg_db_t *this, ike_sa_t *ike_sa, char *imsi);
|
||||
osmo_epdg_ue_t *(*create_subscriber)(osmo_epdg_db_t *this, ike_sa_t *ike_sa);
|
||||
|
||||
/**
|
||||
* Get subscriber by imsi, there might be multiple UE by this IMSI
|
||||
* NULL or UE object. The UE object need to called put() when not used.
|
||||
*/
|
||||
osmo_epdg_ue_t *(*get_subscriber_imsi)(osmo_epdg_db_t *this, char *imsi, int offset);
|
||||
osmo_epdg_ue_t *(*get_subscriber)(osmo_epdg_db_t *this, char *imsi);
|
||||
|
||||
/**
|
||||
* Get subscriber by ike
|
||||
* Get subscriber by imsi via ike_sa, there might be multiple UE by this IMSI
|
||||
* NULL or UE object. The UE object need to called put() when not used.
|
||||
*/
|
||||
osmo_epdg_ue_t *(*get_subscriber_ike)(osmo_epdg_db_t *this, ike_sa_t *ike_sa);
|
||||
|
||||
/**
|
||||
* Get subscriber by id
|
||||
* Remove a subscriber from the db.
|
||||
*/
|
||||
osmo_epdg_ue_t *(*get_subscriber_id)(osmo_epdg_db_t *this, uint32_t id);
|
||||
|
||||
/**
|
||||
* Destroy subscriber by imsi
|
||||
*/
|
||||
void (*destroy_subscriber_ike)(osmo_epdg_db_t *this, ike_sa_t *ike_sa);
|
||||
|
||||
/**
|
||||
* Destroy subscriber by imsi
|
||||
*/
|
||||
void (*destroy_subscriber_id)(osmo_epdg_db_t *this, uint32_t id);
|
||||
|
||||
/**
|
||||
* Destroy subscriber by object
|
||||
*/
|
||||
void (*destroy_subscriber)(osmo_epdg_db_t *this, osmo_epdg_ue_t *ue);
|
||||
void (*remove_subscriber)(osmo_epdg_db_t *this, char *imsi);
|
||||
|
||||
/**
|
||||
* Destroy a osmo_epdg_db_t.
|
||||
|
@ -80,6 +69,6 @@ struct osmo_epdg_db_t {
|
|||
/**
|
||||
* Create a osmo_epdg_db instance.
|
||||
*/
|
||||
osmo_epdg_db_t *osmo_epdg_db_create(osmo_epdg_gsup_client_t *gsup);
|
||||
osmo_epdg_db_t *osmo_epdg_db_create();
|
||||
|
||||
#endif /* OSMO_EPDG_DB_H_ */
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Alexander Couzens <acouzens@sysmocom.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <threading/rwlock.h>
|
||||
#include <utils/utils.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include "osmo_epdg_ue.h"
|
||||
|
||||
typedef struct private_osmo_epdg_ue_t private_osmo_epdg_ue_t;
|
||||
|
||||
|
||||
/**
|
||||
* Private data of an osmo_epdg_ue_t object.
|
||||
*/
|
||||
struct private_osmo_epdg_ue_t {
|
||||
/**
|
||||
* Public osmo_epdg_ue_t interface.
|
||||
*/
|
||||
osmo_epdg_ue_t public;
|
||||
|
||||
/**
|
||||
* a unique id.
|
||||
* Same as ike_sa_t->get_unique_id().
|
||||
*/
|
||||
uint32_t id;
|
||||
|
||||
/**
|
||||
* IMSI encoded as character
|
||||
*/
|
||||
char *imsi;
|
||||
|
||||
/**
|
||||
* IP address of the client. Might become a llist_t in the future
|
||||
*/
|
||||
host_t *address;
|
||||
|
||||
/**
|
||||
* Refcount to track this object.
|
||||
* It will call destroy() when refcount reaches 0
|
||||
*/
|
||||
refcount_t refcount;
|
||||
|
||||
/**
|
||||
* rwlock to lock access for changes
|
||||
*/
|
||||
rwlock_t *lock;
|
||||
|
||||
enum osmo_epdg_ue_state state;
|
||||
};
|
||||
|
||||
METHOD(osmo_epdg_ue_t, get_imsi, const char *,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
return this->imsi;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, set_address, void,
|
||||
private_osmo_epdg_ue_t *this, host_t *address)
|
||||
{
|
||||
this->lock->write_lock(this->lock);
|
||||
if (this->address)
|
||||
{
|
||||
this->address->destroy(this->address);
|
||||
}
|
||||
this->address = address->clone(address);
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, get_address, host_t *,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
host_t *address = NULL;
|
||||
|
||||
this->lock->read_lock(this->lock);
|
||||
if (this->address)
|
||||
{
|
||||
address = this->address->clone(this->address);
|
||||
}
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, set_state, void,
|
||||
private_osmo_epdg_ue_t *this, enum osmo_epdg_ue_state state)
|
||||
{
|
||||
this->lock->write_lock(this->lock);
|
||||
/* TODO: implement a FSM. At least we can get debug information out of it. */
|
||||
this->state = state;
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, get_state, enum osmo_epdg_ue_state,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
enum osmo_epdg_ue_state state;
|
||||
this->lock->read_lock(this->lock);
|
||||
/* TODO: implement a FSM. At least we can get debug information out of it. */
|
||||
state = this->state;
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, get, void,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
ref_get(&this->refcount);
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, put, void,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
if (ref_put(&this->refcount))
|
||||
{
|
||||
this->public.destroy(&this->public);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(osmo_epdg_ue_t, destroy, void,
|
||||
private_osmo_epdg_ue_t *this)
|
||||
{
|
||||
this->lock->destroy(this->lock);
|
||||
free(this);
|
||||
}
|
||||
|
||||
osmo_epdg_ue_t *osmo_epdg_ue_create(uint32_t id, char *imsi)
|
||||
{
|
||||
private_osmo_epdg_ue_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get = _get,
|
||||
.put = _put,
|
||||
.get_imsi = _get_imsi,
|
||||
.get_address = _get_address,
|
||||
.set_address = _set_address,
|
||||
.get_state = _get_state,
|
||||
.set_state = _set_state,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.imsi = strdup(imsi),
|
||||
.id = id,
|
||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||
.state = UE_WAIT_LOCATION_UPDATE,
|
||||
);
|
||||
ref_get(&this->refcount);
|
||||
|
||||
return &this->public;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Alexander Couzens <acouzens@sysmocom.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OSMO_EPDG_UE_H_
|
||||
#define OSMO_EPDG_UE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <networking/host.h>
|
||||
|
||||
/**
|
||||
* @defgroup osmo_epdg_ue osmo_epdg_ue
|
||||
* @{ @ingroup osmo_epdg
|
||||
*/
|
||||
|
||||
typedef struct osmo_epdg_ue_t osmo_epdg_ue_t;
|
||||
|
||||
enum osmo_epdg_ue_state {
|
||||
/* Initial */
|
||||
UE_UNAUTHENTICATED,
|
||||
/* Authenticated */
|
||||
UE_AUTHENTICATED,
|
||||
/* Wait for GSUP Update Location Response */
|
||||
UE_WAIT_LOCATION_UPDATE,
|
||||
/* When the LOCATION UPDATE went successful */
|
||||
UE_LOCATION_UPDATED,
|
||||
/* Wait for GSUP Tunnel Response */
|
||||
UE_WAIT_TUNNEL,
|
||||
/* Tunnel Succeeded */
|
||||
UE_TUNNEL_READY,
|
||||
/* Everything ready, data can flow */
|
||||
UE_CONNECTED,
|
||||
/* Notify the osmo-epdg about destruction, wait for an answer */
|
||||
UE_DISCONNECTING,
|
||||
/* When the UE failed, but the IKE_SA hasn't been destroyed */
|
||||
UE_FAIL,
|
||||
UE_DESTROYED,
|
||||
};
|
||||
|
||||
/**
|
||||
* UE object
|
||||
*/
|
||||
struct osmo_epdg_ue_t {
|
||||
/**
|
||||
* Get IMSI
|
||||
*/
|
||||
const char *(*get_imsi)(osmo_epdg_ue_t *this);
|
||||
|
||||
/**
|
||||
* Get address. Returns NULL or a cloned' host_t object
|
||||
*/
|
||||
host_t *(*get_address)(osmo_epdg_ue_t *this);
|
||||
|
||||
/**
|
||||
* Set address. It will internally clone the given object.
|
||||
*/
|
||||
void (*set_address)(osmo_epdg_ue_t *this, host_t *address);
|
||||
|
||||
/**
|
||||
* Get state
|
||||
*/
|
||||
enum osmo_epdg_ue_state (*get_state)(osmo_epdg_ue_t *this);
|
||||
|
||||
/**
|
||||
* Set state
|
||||
*/
|
||||
void (*set_state)(osmo_epdg_ue_t *this, enum osmo_epdg_ue_state state);
|
||||
|
||||
|
||||
/**
|
||||
* Increase the internal refcount. Use put() when done with the object
|
||||
*/
|
||||
void (*get)(osmo_epdg_ue_t *this);
|
||||
|
||||
/**
|
||||
* Decrease the internal refcount.
|
||||
* When reaching zero, the object will be destroyed.
|
||||
*/
|
||||
void (*put)(osmo_epdg_ue_t *this);
|
||||
|
||||
/**
|
||||
* Destroy a osmo_epdg_db_t. Use get/put to track it. Don't use destroy().
|
||||
* TODO: maybe remove destroy() completely.
|
||||
*/
|
||||
void (*destroy)(osmo_epdg_ue_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a osmo_epdg_ue instance.
|
||||
* A newly created object will come with refcount = 1. Use put() to destroy it.
|
||||
*/
|
||||
osmo_epdg_ue_t *osmo_epdg_ue_create(uint32_t id, char *imsi);
|
||||
|
||||
#endif /* OSMO_EPDG_UE_H_ */
|
|
@ -24,38 +24,8 @@
|
|||
#include <utils/chunk.h>
|
||||
#include <utils/identification.h>
|
||||
|
||||
|
||||
#define IPA_ALLOC_SIZE 1200
|
||||
|
||||
enum ue_state {
|
||||
/* Initial */
|
||||
UE_UNAUTHENTICATED,
|
||||
/* Authenticated */
|
||||
UE_AUTHENTICATED,
|
||||
/* Wait for GSUP Update Location Request */
|
||||
UE_WAIT_LOCATION_UPDATE,
|
||||
/* Wait for GSUP Tunnel Request */
|
||||
UE_WAIT_TUNNEL,
|
||||
/* Everything ready, data can flow */
|
||||
UE_CONNECTED,
|
||||
/* Notify the osmo-epdg about destruction, wait for an answer */
|
||||
UE_DISCONNECTING,
|
||||
UE_DESTROYED,
|
||||
};
|
||||
|
||||
/* TODO: how to clean up/garbage collect */
|
||||
struct osmo_epdg_ue {
|
||||
/* increasing uniq id */
|
||||
uint32_t id;
|
||||
/* imsi should be uniq, need protected against fake UE */
|
||||
char *imsi;
|
||||
enum ue_state state;
|
||||
|
||||
/* TODO: missing strongswan session pointer */
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
typedef struct osmo_epdg_ue osmo_epdg_ue_t;
|
||||
|
||||
struct msgb *chunk_to_msgb(chunk_t *chunk);
|
||||
int get_imsi(identification_t *id, char *imsi, size_t imsi_len);
|
||||
int get_imsi_ike(ike_sa_t *ike_sa, char *imsi, size_t imsi_len);
|
||||
|
|
Loading…
Reference in New Issue