Asterisk - The Open Source Telephony Project  21.4.1
func_scramble.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Naveen Albert
5  *
6  * Naveen Albert <asterisk@phreaknet.org>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Frequency inverter
22  *
23  * \author Naveen Albert <asterisk@phreaknet.org>
24  *
25  * \ingroup functions
26  *
27  */
28 
29 /*** MODULEINFO
30  <support_level>extended</support_level>
31  ***/
32 
33 /*** DOCUMENTATION
34  <function name="SCRAMBLE" language="en_US">
35  <since>
36  <version>16.21.0</version>
37  <version>18.7.0</version>
38  <version>19.0.0</version>
39  </since>
40  <synopsis>
41  Scrambles audio on a channel.
42  </synopsis>
43  <syntax>
44  <parameter name="direction" required="false">
45  <para>Must be <literal>TX</literal> or <literal>RX</literal>
46  to limit to a specific direction, or <literal>both</literal>
47  for both directions. <literal>remove</literal>
48  will remove an existing scrambler.</para>
49  </parameter>
50  </syntax>
51  <description>
52  <para>Scrambles audio on a channel using whole spectrum inversion.
53  This is not intended to be used for securely scrambling
54  audio. It merely renders obfuscates audio on a channel
55  to render it unintelligible, as a privacy enhancement.</para>
56  </description>
57  <see-also>
58  <ref type="application">ChanSpy</ref>
59  </see-also>
60  </function>
61  ***/
62 
63 #include "asterisk.h"
64 
65 #include "asterisk/module.h"
66 #include "asterisk/channel.h"
67 #include "asterisk/pbx.h"
68 #include "asterisk/utils.h"
69 #include "asterisk/audiohook.h"
70 #include "asterisk/app.h"
71 
72 #include <stdio.h>
73 #include <string.h>
74 
76  struct ast_audiohook audiohook;
77  unsigned short int tx;
78  unsigned short int rx;
79  unsigned short int state;
80 };
81 
82 static void destroy_callback(void *data)
83 {
84  struct scramble_information *ni = data;
85 
86  /* Destroy the audiohook, and destroy ourselves */
87  ast_audiohook_lock(&ni->audiohook);
88  ast_audiohook_detach(&ni->audiohook);
89  ast_audiohook_unlock(&ni->audiohook);
90  ast_audiohook_destroy(&ni->audiohook);
91  ast_free(ni);
92 
93  return;
94 }
95 
96 /*! \brief Static structure for datastore information */
97 static const struct ast_datastore_info scramble_datastore = {
98  .type = "scramble",
99  .destroy = destroy_callback
100 };
101 
102 /* modifies buffer pointed to by 'amp' with inverted values */
103 static inline void freq_invert(short *amp, int samples)
104 {
105  int i;
106  /* invert every other sample by 1 */
107  for (i = 0; i < samples; i += 2) {
108  amp[i] = -amp[i];
109  }
110 }
111 
112 static int scramble_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
113 {
114  struct ast_datastore *datastore = NULL;
115  struct scramble_information *ni = NULL;
116 
117  /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
118  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
119  return 0;
120  }
121 
122  /* Grab datastore which contains our gain information */
123  if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL))) {
124  return 0;
125  }
126 
127  if (frame->frametype == AST_FRAME_VOICE) { /* only invert voice frequencies */
128  ni = datastore->data;
129  /* Based on direction of frame, and confirm it is applicable */
130  if (!(direction == AST_AUDIOHOOK_DIRECTION_READ ? ni->rx : ni->tx)) {
131  return 0;
132  }
133  /* Scramble the sample now */
134  freq_invert(frame->data.ptr, frame->samples);
135  }
136  return 0;
137 }
138 
139 /*! \internal \brief Disable scrambling on the channel */
140 static int remove_scrambler(struct ast_channel *chan)
141 {
142  struct ast_datastore *datastore = NULL;
143  struct scramble_information *data;
144  SCOPED_CHANNELLOCK(chan_lock, chan);
145 
146  datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL);
147  if (!datastore) {
148  ast_log(AST_LOG_WARNING, "Cannot remove SCRAMBLE from %s: SCRAMBLE not currently enabled\n",
149  ast_channel_name(chan));
150  return -1;
151  }
152  data = datastore->data;
153 
154  if (ast_audiohook_remove(chan, &data->audiohook)) {
155  ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE audiohook from channel %s\n", ast_channel_name(chan));
156  return -1;
157  }
158 
159  if (ast_channel_datastore_remove(chan, datastore)) {
160  ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE datastore from channel %s\n",
161  ast_channel_name(chan));
162  return -1;
163  }
164  ast_datastore_free(datastore);
165 
166  return 0;
167 }
168 
169 static int scramble_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
170 {
171  char *parse;
172  struct ast_datastore *datastore = NULL;
173  struct scramble_information *ni = NULL;
174  int tx = 1, rx = 1;
175 
177  AST_APP_ARG(direction);
178  );
179 
180  if (!chan) {
181  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
182  return -1;
183  }
184 
185  parse = ast_strdupa(value);
186  AST_STANDARD_APP_ARGS(args, parse);
187 
188  if (!strcasecmp(args.direction, "remove")) {
189  return remove_scrambler(chan);
190  }
191  if (!strcasecmp(args.direction, "tx")) {
192  tx = 1;
193  rx = 0;
194  } else if (!strcasecmp(args.direction, "rx")) {
195  rx = 0;
196  tx = 1;
197  } else if (strcasecmp(args.direction, "both")) {
198  ast_log(LOG_ERROR, "Direction must be either RX, TX, both, or remove\n");
199  return -1;
200  }
201  ast_channel_lock(chan);
202  if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL))) {
203  /* Allocate a new datastore to hold the reference to this audiohook information */
204  if (!(datastore = ast_datastore_alloc(&scramble_datastore, NULL))) {
205  return 0;
206  }
207  if (!(ni = ast_calloc(1, sizeof(*ni)))) {
208  ast_datastore_free(datastore);
209  return 0;
210  }
212  ni->audiohook.manipulate_callback = scramble_callback;
213  datastore->data = ni;
214  ast_channel_datastore_add(chan, datastore);
215  ast_audiohook_attach(chan, &ni->audiohook);
216  } else {
217  ni = datastore->data;
218  }
219  ni->tx = tx;
220  ni->rx = rx;
221  ast_channel_unlock(chan);
222 
223  return 0;
224 }
225 
226 static struct ast_custom_function scramble_function = {
227  .name = "SCRAMBLE",
228  .write = scramble_write,
229 };
230 
231 static int unload_module(void)
232 {
233  return ast_custom_function_unregister(&scramble_function);
234 }
235 
236 static int load_module(void)
237 {
238  return ast_custom_function_register(&scramble_function);
239 }
240 
241 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frequency inverting voice scrambler");
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
Main Channel structure associated with a channel.
static const struct ast_datastore_info scramble_datastore
Static structure for datastore information.
Definition: func_scramble.c:97
Asterisk main include file. File version handling, generic pbx functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Audiohooks Architecture.
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:721
Structure for a data store type.
Definition: datastore.h:31
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Utility functions.
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:118
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
Core PBX routines and definitions.
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
static void destroy_callback(void *data)
Helper function used by datastores to destroy the speech structure upon hangup.
union ast_frame::@224 data
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
ast_audiohook_direction
Definition: audiohook.h:48
void * data
Definition: datastore.h:66
Data structure associated with a single frame of data.
enum ast_audiohook_status status
Definition: audiohook.h:108
enum ast_frame_type frametype
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define AST_APP_ARG(name)
Define an application argument.