Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion ci/tsqa/tests/test_https.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

from OpenSSL import SSL
import socket

import time
import helpers
import tsqa.utils
import os
import logging
unittest = tsqa.utils.import_unittest()

log = logging.getLogger(__name__)
# some ciphers to test with
CIPHER_MAP = {
'rsa': 'ECDHE-RSA-AES256-GCM-SHA384',
Expand Down Expand Up @@ -273,3 +276,66 @@ def test_intermediate_ca_rsa(self):

def test_intermediate_ca_ecdsa(self):
self._intermediate_ca_t('ecdsa')


class TestConfigFileGroup(helpers.EnvironmentCase, CertSelectionMixin):
'''
Tests for config file group with https
The config file group includes a parent file ssl_multicert.config and some children files.
when the content of a child file is updated but the file name hasn't been changed.
The behavior is the same as the parent file in the group has been changed.
In the test, a child file named www.unknown.com.pem, which is rsa_keys/www.test.com.pem at first,
is updated to ec_keys/www.test.com.pem.
The difference can be told by different results from calling get_cert() with different ciphers as paramters
'''
@classmethod
def setUpEnv(cls, env):
# add an SSL port to ATS
cls.ssl_port = tsqa.utils.bind_unused_port()[1]
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports'] += ' {0}:ssl'.format(cls.ssl_port)
cls.configs['records.config']['CONFIG'].update({
'proxy.config.diags.debug.enabled': 1,
'proxy.config.diags.debug.tags': 'ssl',
'proxy.config.ssl.server.cipher_suite': '{0}:{1}'.format(CIPHER_MAP['ecdsa'], CIPHER_MAP['rsa']),
})
cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0},{1} ssl_ca_name={2},{3}'.format(
helpers.tests_file_path('rsa_keys/www.example.com.pem'),
helpers.tests_file_path('ec_keys/www.example.com.pem'),
helpers.tests_file_path('rsa_keys/intermediate.crt'),
helpers.tests_file_path('ec_keys/intermediate.crt'),
))
cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.3 ssl_cert_name={0}'.format(
helpers.tests_file_path('www.unknown.com.pem'),
))
os.system('cp %s %s' % (helpers.tests_file_path('rsa_keys/www.test.com.pem'), helpers.tests_file_path('www.unknown.com.pem')))
log.info('cp %s %s' % (helpers.tests_file_path('rsa_keys/www.test.com.pem'), helpers.tests_file_path('www.unknown.com.pem')))

def test_config_file_group(self):
signal_cmd = os.path.join(self.environment.layout.bindir, 'traffic_line') + ' -x'
addr = ('127.0.0.3', self.ssl_port)
cert = self._get_cert(addr, ciphers=CIPHER_MAP['rsa'])
self.assertEqual(cert.get_subject().commonName.decode(), 'www.test.com')
with self.assertRaises(Exception):
self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
time.sleep(5)
os.system('cp %s %s' % (helpers.tests_file_path('ec_keys/www.test.com.pem'), helpers.tests_file_path('www.unknown.com.pem')))
log.info('cp %s %s' % (helpers.tests_file_path('ec_keys/www.test.com.pem'), helpers.tests_file_path('www.unknown.com.pem')))
os.system(signal_cmd)
log.info(signal_cmd)
# waiting for the reconfiguration completed
sec = 0
while True:
time.sleep(5)
sec += 5
log.info("reloading: %d seconds" % (sec))
self.assertLess(sec, 30)
try:
self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
break
except:
continue
cert = self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
self.assertEqual(cert.get_subject().commonName.decode(), 'www.test.com')
with self.assertRaises(Exception):
self._get_cert(addr, ciphers=CIPHER_MAP['rsa'])
os.system('rm %s' %(helpers.tests_file_path('www.unknown.com.pem')))
7 changes: 7 additions & 0 deletions iocore/net/P_SSLConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct SSLCertLookup;


typedef void (*init_ssl_ctx_func)(void *, bool);
typedef void (*load_ssl_file_func)(const char *, unsigned int);

struct SSLConfigParams : public ConfigInfo {
enum SSL_SESSION_CACHE_MODE {
Expand All @@ -55,6 +56,11 @@ struct SSLConfigParams : public ConfigInfo {
SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL = 2
};

enum SSL_CONFIG_VERISON_MODE {
SSL_CONFIG_UNVERISONED = 0,
SSL_CONFIG_VERISONED = 1
};

SSLConfigParams();
virtual ~SSLConfigParams();

Expand Down Expand Up @@ -107,6 +113,7 @@ struct SSLConfigParams : public ConfigInfo {
static char *ssl_wire_trace_server_name;

static init_ssl_ctx_func init_ssl_ctx_cb;
static load_ssl_file_func load_ssl_file_cb;

void initialize();
void cleanup();
Expand Down
1 change: 1 addition & 0 deletions iocore/net/SSLConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ size_t SSLConfigParams::session_cache_number_buckets = 1024;
bool SSLConfigParams::session_cache_skip_on_lock_contention = false;
size_t SSLConfigParams::session_cache_max_bucket_size = 100;
init_ssl_ctx_func SSLConfigParams::init_ssl_ctx_cb = NULL;
load_ssl_file_func SSLConfigParams::load_ssl_file_cb = NULL;

// TS-3534 Wiretracing for SSL Connections
int SSLConfigParams::ssl_wire_trace_enabled = 0;
Expand Down
4 changes: 4 additions & 0 deletions iocore/net/SSLUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,7 @@ SSLPrivateKeyHandler(SSL_CTX *ctx, const SSLConfigParams *params, const ats_scop
SSLError("failed to load server private key from %s", (const char *)completeServerKeyPath);
return false;
}
SSLConfigParams::load_ssl_file_cb(completeServerKeyPath, SSLConfigParams::SSL_CONFIG_UNVERISONED);
} else {
SSLError("empty SSL private key path in records.config");
return false;
Expand Down Expand Up @@ -1376,6 +1377,7 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config &sslMu
goto fail;
}
certList.push_back(cert);
SSLConfigParams::load_ssl_file_cb(completeServerCertPath, SSLConfigParams::SSL_CONFIG_UNVERISONED);
// Load up any additional chain certificates
X509 *ca;
while ((ca = PEM_read_bio_X509(bio.get(), NULL, 0, NULL))) {
Expand All @@ -1398,6 +1400,7 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config &sslMu
SSLError("failed to load global certificate chain from %s", (const char *)completeServerCertChainPath);
goto fail;
}
SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, SSLConfigParams::SSL_CONFIG_UNVERISONED);
}

// Now, load any additional certificate chains specified in this entry.
Expand All @@ -1407,6 +1410,7 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config &sslMu
SSLError("failed to load certificate chain from %s", (const char *)completeServerCertChainPath);
goto fail;
}
SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, SSLConfigParams::SSL_CONFIG_UNVERISONED);
}
}

Expand Down
4 changes: 3 additions & 1 deletion mgmt/BaseManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#include "ts/ink_hash_table.h"

#include "MgmtDefs.h"

#include "MgmtMarshall.h"

/*******************************************
* used by LocalManager and in Proxy Main. *
Expand Down Expand Up @@ -100,6 +100,8 @@
#define MGMT_SIGNAL_HTTP_CONGESTED_SERVER 20 /* Congestion control -- congested server */
#define MGMT_SIGNAL_HTTP_ALLEVIATED_SERVER 21 /* Congestion control -- alleviated server */

#define MGMT_SIGNAL_CONFIG_FILE_CHILD 22

#define MGMT_SIGNAL_SAC_SERVER_DOWN 400

typedef struct _mgmt_message_hdr_type {
Expand Down
88 changes: 73 additions & 15 deletions mgmt/FileManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ FileManager::registerCallback(FileCallbackFunc func)
ink_mutex_release(&cbListLock);
}

// void FileManager::addFile(char* baseFileName, const configFileInfo* file_info)
// void FileManager::addFile(char* fileName, const configFileInfo* file_info,
// Rollback* parentRollback)
//
// for the baseFile, creates a Rollback object for it
//
Expand All @@ -135,47 +136,54 @@ FileManager::registerCallback(FileCallbackFunc func)
// Pointers to the new objects are stored in the bindings hashtable
//
void
FileManager::addFile(const char *baseFileName, bool root_access_needed)
FileManager::addFile(const char *fileName, bool root_access_needed, Rollback *parentRollback, RollBackVersionType version_type)
{
ink_assert(baseFileName != NULL);
ink_mutex_acquire(&accessLock);
addFileHelper(fileName, root_access_needed, parentRollback, version_type);
ink_mutex_release(&accessLock);
}

Rollback *rb = new Rollback(baseFileName, root_access_needed);
// caller must hold the lock
void
FileManager::addFileHelper(const char *fileName, bool root_access_needed, Rollback *parentRollback, RollBackVersionType version_type)
{
ink_assert(fileName != NULL);

Rollback *rb = new Rollback(fileName, root_access_needed, parentRollback, version_type);
rb->configFiles = this;

ink_mutex_acquire(&accessLock);
ink_hash_table_insert(bindings, baseFileName, rb);
ink_mutex_release(&accessLock);
ink_hash_table_insert(bindings, fileName, rb);
}

// bool FileManager::getRollbackObj(char* baseFileName, Rollback** rbPtr)
// bool FileManager::getRollbackObj(char* fileName, Rollback** rbPtr)
//
// Sets rbPtr to the rollback object associated
// with the passed in baseFileName.
// with the passed in fileName.
//
// If there is no binding, falseis returned
//
bool
FileManager::getRollbackObj(const char *baseFileName, Rollback **rbPtr)
FileManager::getRollbackObj(const char *fileName, Rollback **rbPtr)
{
InkHashTableValue lookup = NULL;
int found;

ink_mutex_acquire(&accessLock);
found = ink_hash_table_lookup(bindings, baseFileName, &lookup);
found = ink_hash_table_lookup(bindings, fileName, &lookup);
ink_mutex_release(&accessLock);

*rbPtr = (Rollback *)lookup;
return (found == 0) ? false : true;
}

// bool FileManager::fileChanged(const char* baseFileName)
// bool FileManager::fileChanged(const char* fileName)
//
// Called by the Rollback class whenever a a config has changed
// Initiates callbacks
//
//
void
FileManager::fileChanged(const char *baseFileName, bool incVersion)
FileManager::fileChanged(const char *fileName, bool incVersion)
{
callbackListable *cb;
char *filenameCopy;
Expand All @@ -185,7 +193,7 @@ FileManager::fileChanged(const char *baseFileName, bool incVersion)
for (cb = cblist.head; cb != NULL; cb = cb->link.next) {
// Dup the string for each callback to be
// defensive incase it modified when it is not supposed to be
filenameCopy = ats_strdup(baseFileName);
filenameCopy = ats_strdup(fileName);
(*cb->func)(filenameCopy, incVersion);
ats_free(filenameCopy);
}
Expand Down Expand Up @@ -625,14 +633,44 @@ FileManager::rereadConfig()
InkHashTableEntry *entry;
InkHashTableIteratorState iterator_state;

Vec<Rollback *> changedFiles;
Vec<Rollback *> parentFileNeedChange;
ink_mutex_acquire(&accessLock);
for (entry = ink_hash_table_iterator_first(bindings, &iterator_state); entry != NULL;
entry = ink_hash_table_iterator_next(bindings, &iterator_state)) {
rb = (Rollback *)ink_hash_table_entry_value(bindings, entry);
rb->checkForUserUpdate(ROLLBACK_CHECK_AND_UPDATE);
if (rb->checkForUserUpdate(rb->getVersionType() == ROLLBACK_UNVERSIONED ? ROLLBACK_CHECK_ONLY : ROLLBACK_CHECK_AND_UPDATE)) {
changedFiles.push_back(rb);
if (rb->isChildRollback()) {
parentFileNeedChange.add_exclusive(rb->getParentRollback());
}
}
}

Vec<Rollback *> childFileNeedDelete;
for (size_t i = 0; i < changedFiles.n; i++) {
if (changedFiles[i]->isChildRollback())
continue;
// for each parent file, if it is changed, then delete all its children
for (entry = ink_hash_table_iterator_first(bindings, &iterator_state); entry != NULL;
entry = ink_hash_table_iterator_next(bindings, &iterator_state)) {
rb = (Rollback *)ink_hash_table_entry_value(bindings, entry);
if (rb->getParentRollback() == changedFiles[i]) {
childFileNeedDelete.add_exclusive(rb);
}
}
}
for (size_t i = 0; i < childFileNeedDelete.n; i++) {
ink_hash_table_delete(bindings, childFileNeedDelete[i]->getFileName());
delete childFileNeedDelete[i];
}
ink_mutex_release(&accessLock);

for (size_t i = 0; i < parentFileNeedChange.n; i++) {
if (!changedFiles.in(parentFileNeedChange[i])) {
fileChanged(parentFileNeedChange[i]->getFileName(), true);
}
}
// INKqa11910
// need to first check that enable_customizations is enabled
bool found;
Expand Down Expand Up @@ -716,6 +754,26 @@ FileManager::createSelect(char *action, textBuffer *output, ExpandingArray *opti
}
}

// void configFileChild(const char *parent, const char *child)
//
// Add child to the bindings with parentRollback
void
FileManager::configFileChild(const char *parent, const char *child, unsigned int options)
{
InkHashTableValue lookup;
Rollback *parentRollback = NULL;
ink_mutex_acquire(&accessLock);
int htfound = ink_hash_table_lookup(bindings, parent, &lookup);
if (htfound) {
parentRollback = (Rollback *)lookup;
}
RollBackVersionType version_type = options ? ROLLBACK_VERSIONED : ROLLBACK_UNVERSIONED;
if (htfound) {
addFileHelper(child, true, parentRollback, version_type);
}
ink_mutex_release(&accessLock);
}

// bool checkValidName(const char* name)
//
// if the string is invalid, ie. all white spaces or contains "irregular" chars,
Expand Down
18 changes: 11 additions & 7 deletions mgmt/FileManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "ts/ink_hash_table.h"
#include "ts/List.h"
#include "Rollback.h"
#include "ts/Vec.h"
#include "MultiFile.h"

class Rollback;
Expand Down Expand Up @@ -80,19 +81,19 @@ class ExpandingArray;
// is also created
//
// getRollbckObj(char* , RollbackPtr**) - sets *rbPtr to Rollback
// object bound to baseFileName. Returns true if there is
// object bound to fileName. Returns true if there is
// a binding and false otherwise
//
// getWFEObj(char*, WebFileEdit**) - sets *wfePtr to WebFileEdit
// object bound to baseFileName. Returns true if there is
// object bound to fileName. Returns true if there is
// a binding and false otherwise
//
// registerCallback(FileCallbackFunc) - registers a callback function
// which will get called everytime a managed file changes. The
// callback function should NOT use the calling thread to
// access any Rollback objects or block for a long time
//
// fileChanged(const char* baseFileName) - called by Rollback objects
// fileChanged(const char* fileName) - called by Rollback objects
// when their contents change. Triggers callbacks to FileCallbackFuncs
//
// filesManaged() - returns a textBuffer that contains a new line separated
Expand All @@ -110,16 +111,16 @@ class ExpandingArray;
//
// rereadConfig() - Checks all managed files to see if they have been
// updated
//
// addConfigFileGroup(char* data_str, int data_size) - update config file group infos
class FileManager : public MultiFile
{
public:
FileManager();
~FileManager();
void addFile(const char *baseFileName, bool root_access_needed);
bool getRollbackObj(const char *baseFileName, Rollback **rbPtr);
void addFile(const char *fileName, bool root_access_needed, Rollback *parentRollback = NULL, RollBackVersionType version_type = ROLLBACK_VERSIONED);
bool getRollbackObj(const char *fileName, Rollback **rbPtr);
void registerCallback(FileCallbackFunc func);
void fileChanged(const char *baseFileName, bool incVersion);
void fileChanged(const char *fileName, bool incVersion);
textBuffer *filesManaged();
void rereadConfig();
bool isConfigStale();
Expand All @@ -131,6 +132,7 @@ class FileManager : public MultiFile
SnapResult removeSnap(const char *snapName, const char *snapDir);
void displaySnapOption(textBuffer *output);
SnapResult WalkSnaps(ExpandingArray *snapList);
void configFileChild(const char *parent, const char *child, unsigned int options);

private:
void doRollbackLocks(lockAction_t action);
Expand All @@ -147,6 +149,8 @@ class FileManager : public MultiFile
void snapSuccessResponse(char *action, textBuffer *output);
void generateRestoreConfirm(char *snapName, textBuffer *output);
bool checkValidName(const char *name);
const char *getParentFileName(const char *fileName);
void addFileHelper(const char *fileName, bool root_access_needed, Rollback *parentRollback, RollBackVersionType version_type);
};

int snapEntryCmpFunc(const void *e1, const void *e2);
Expand Down
Loading